diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/AddressBase58.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/AddressBase58.java index f070af1e7..a4481a5a8 100644 --- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/AddressBase58.java +++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/AddressBase58.java @@ -9,9 +9,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -56,7 +56,7 @@ public static String encode( Objects.requireNonNull(expectedLength); if (expectedLength.intValue() != bytes.getUnsignedBytes().size()) { - throw new EncodeException("Length of bytes does not match expectedLength."); + throw new EncodeException(String.format("Length of bytes does not match expectedLength of %s.", expectedLength)); } return encodeChecked(bytes.toByteArray(), versions); @@ -99,6 +99,7 @@ public static String encodeChecked(final byte[] bytes, final List versi * @param version The {@link Version} to try decoding with. * * @return A {@link Decoded} containing the decoded value and version. + * * @throws EncodingFormatException If the version bytes of the Base58 value are invalid. */ public static Decoded decode( @@ -136,14 +137,14 @@ public static Decoded decode( * Decode a Base58Check {@link String}. * * @param base58Value The Base58Check encoded {@link String} to be decoded. - * @param keyTypes A {@link List} of {@link KeyType}s which can be associated with the result of this - * method. + * @param keyTypes A {@link List} of {@link KeyType}s which can be associated with the result of this method. * @param versions A {@link List} of {@link Version}s to try decoding with. * @param expectedLength The expected length of the decoded value. * * @return A {@link Decoded} containing the decoded value, version, and type. - * @throws EncodingFormatException If more than one version is supplied without an expectedLength value present, - * or if the version bytes of the Base58 value are invalid. + * + * @throws EncodingFormatException If more than one version is supplied without an expectedLength value present, or if + * the version bytes of the Base58 value are invalid. */ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public static Decoded decode( diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/AddressCodec.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/AddressCodec.java index b7ea342d3..941d14911 100644 --- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/AddressCodec.java +++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/AddressCodec.java @@ -9,9 +9,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -86,7 +86,10 @@ public UnsignedByteArray decodeAccountId(final Address accountId) { * @param publicKey An {@link UnsignedByteArray} containing the public key to be encoded. * * @return The Base58 representation of publicKey. + * + * @deprecated Prefer {@link PublicKeyCodec#encodeNodePublicKey(UnsignedByteArray)}. */ + @Deprecated public String encodeNodePublicKey(final UnsignedByteArray publicKey) { Objects.requireNonNull(publicKey); @@ -101,7 +104,9 @@ public String encodeNodePublicKey(final UnsignedByteArray publicKey) { * @return An {@link UnsignedByteArray} containing the decoded public key. * * @see "https://xrpl.org/base58-encodings.html" + * @deprecated Prefer {@link PublicKeyCodec#decodeNodePublicKey(String)}. */ + @Deprecated public UnsignedByteArray decodeNodePublicKey(final String publicKey) { Objects.requireNonNull(publicKey); diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/PrivateKeyCodec.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/PrivateKeyCodec.java new file mode 100644 index 000000000..9a7abf98a --- /dev/null +++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/PrivateKeyCodec.java @@ -0,0 +1,111 @@ +package org.xrpl.xrpl4j.codec.addresses; + +/*- + * ========================LICENSE_START================================= + * xrpl4j :: core + * %% + * Copyright (C) 2020 - 2023 XRPL Foundation and its contributors + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * =========================LICENSE_END================================== + */ + +import com.google.common.collect.Lists; +import com.google.common.primitives.UnsignedInteger; + +import java.util.Objects; + +/** + * A Codec for encoding/decoding various seed primitives. + */ +public class PrivateKeyCodec { + + private static final PrivateKeyCodec INSTANCE = new PrivateKeyCodec(); + + public static PrivateKeyCodec getInstance() { + return INSTANCE; + } + + /** + * Encode an XRPL Node Private Key to a Base58Check encoded {@link String}. + * + * @param privateKeyBytes An {@link UnsignedByteArray} containing the public key to be encoded. + * + * @return The Base58 representation of privateKeyBytes. + */ + public String encodeNodePrivateKey(final UnsignedByteArray privateKeyBytes) { + Objects.requireNonNull(privateKeyBytes); + + return AddressBase58.encode( + privateKeyBytes, + Lists.newArrayList(Version.NODE_PRIVATE), + UnsignedInteger.valueOf(32) + ); + } + + /** + * Decode a Base58Check encoded XRPL Node Private Key. + * + * @param privateKeyBytes The Base58 encoded public key to be decoded. + * + * @return An {@link UnsignedByteArray} containing the decoded public key. + * + * @see "https://xrpl.org/base58-encodings.html" + */ + public UnsignedByteArray decodeNodePrivateKey(final String privateKeyBytes) { + Objects.requireNonNull(privateKeyBytes); + + return AddressBase58.decode( + privateKeyBytes, + Lists.newArrayList(Version.NODE_PRIVATE), + UnsignedInteger.valueOf(32) + ).bytes(); + } + + /** + * Encode an XRPL Account Private Key to a Base58Check encoded {@link String}. + * + * @param privateKeyBytes An {@link UnsignedByteArray} containing the public key to be encoded. + * + * @return The Base58 representation of privateKeyBytes. + */ + public String encodeAccountPrivateKey(final UnsignedByteArray privateKeyBytes) { + Objects.requireNonNull(privateKeyBytes); + + return AddressBase58.encode( + privateKeyBytes, + Lists.newArrayList(Version.ACCOUNT_SECRET_KEY), + UnsignedInteger.valueOf(32) + ); + } + + /** + * Decode a Base58Check encoded XRPL Account Private Key. + * + * @param publicKey The Base58 encoded public key to be decoded. + * + * @return An {@link UnsignedByteArray} containing the decoded public key. + * + * @see "https://xrpl.org/base58-encodings.html" + */ + public UnsignedByteArray decodeAccountPrivateKey(final String publicKey) { + Objects.requireNonNull(publicKey); + + return AddressBase58.decode( + publicKey, + Lists.newArrayList(Version.ACCOUNT_SECRET_KEY), + UnsignedInteger.valueOf(32) + ).bytes(); + } + +} diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/PublicKeyCodec.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/PublicKeyCodec.java index 9bb369ee2..0dff88cfa 100644 --- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/PublicKeyCodec.java +++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/PublicKeyCodec.java @@ -9,9 +9,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,7 +28,6 @@ /** * A Codec for encoding/decoding various seed primitives. */ -@SuppressWarnings( {"OptionalUsedAsFieldOrParameterType", "ParameterName", "MethodName"}) public class PublicKeyCodec { private static final PublicKeyCodec INSTANCE = new PublicKeyCodec(); @@ -46,7 +45,12 @@ public static PublicKeyCodec getInstance() { */ public String encodeNodePublicKey(final UnsignedByteArray publicKey) { Objects.requireNonNull(publicKey); - return AddressBase58.encode(publicKey, Lists.newArrayList(Version.NODE_PUBLIC), UnsignedInteger.valueOf(33)); + + return AddressBase58.encode( + publicKey, + Lists.newArrayList(Version.NODE_PUBLIC), + UnsignedInteger.valueOf(33) + ); } /** @@ -78,7 +82,11 @@ public UnsignedByteArray decodeNodePublicKey(final String publicKey) { public String encodeAccountPublicKey(final UnsignedByteArray publicKey) { Objects.requireNonNull(publicKey); - return AddressBase58.encode(publicKey, Lists.newArrayList(Version.ACCOUNT_PUBLIC_KEY), UnsignedInteger.valueOf(33)); + return AddressBase58.encode( + publicKey, + Lists.newArrayList(Version.ACCOUNT_PUBLIC_KEY), + UnsignedInteger.valueOf(33) + ); } /** diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/Version.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/Version.java index 25c828edb..48558b2db 100644 --- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/Version.java +++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/codec/addresses/Version.java @@ -23,10 +23,12 @@ public enum Version { ED25519_SEED(new int[] {0x01, 0xE1, 0x4B}), - FAMILY_SEED(new int[] {0x21}), + FAMILY_SEED(new int[] {0x21}), // 33 in decimal ACCOUNT_ID(new int[] {0}), - NODE_PUBLIC(new int[] {0x1C}), - ACCOUNT_PUBLIC_KEY(new int[] {0x23}); + NODE_PUBLIC(new int[] {0x1C}), // 28 in decimal + NODE_PRIVATE(new int[] {0x20}), // 32 in decimal + ACCOUNT_SECRET_KEY(new int[] {0x22}), // 34 in decimal + ACCOUNT_PUBLIC_KEY(new int[] {0x23}); // 35 in decimal private final int[] values; diff --git a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/crypto/keys/PrivateKey.java b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/crypto/keys/PrivateKey.java index c7aad5cee..00bfd34a5 100644 --- a/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/crypto/keys/PrivateKey.java +++ b/xrpl4j-core/src/main/java/org/xrpl/xrpl4j/crypto/keys/PrivateKey.java @@ -21,10 +21,12 @@ */ import com.google.common.base.Preconditions; +import com.google.common.hash.HashCode; import org.xrpl.xrpl4j.codec.addresses.KeyType; import org.xrpl.xrpl4j.codec.addresses.UnsignedByte; import org.xrpl.xrpl4j.codec.addresses.UnsignedByteArray; +import java.security.Key; import java.util.Objects; /** @@ -60,26 +62,64 @@ public class PrivateKey implements PrivateKeyable, javax.security.auth.Destroyab public static final UnsignedByte SECP256K1_PREFIX = UnsignedByte.of(0x00); private final UnsignedByteArray value; + + private final KeyType keyType; + private boolean destroyed; + private static final String CONSTRUCTOR_ERROR_MESSAGE = + "Constructing a PrivateKey with raw bytes requires a one-byte prefix in front of the 32 natural bytes of a" + + " private key. Use the prefix `0xED` for ed25519 private keys, or `0x00` for secp256k1 private keys."; + /** - * Instantiates a new instance of {@link PrivateKey} using the supplied bytes. + * Instantiates a new instance of {@link PrivateKey} using the supplied 32 bytes and specified key type. * - * @param value An {@link UnsignedByteArray} containing this key's binary value. + * @param value An {@link UnsignedByteArray} containing a private key's natural bytes (i.e., 32 bytes). + * @param keyType A {@link KeyType} for this private key. * * @return A {@link PrivateKey}. */ - public static PrivateKey of(final UnsignedByteArray value) { + public static PrivateKey fromNaturalBytes(final UnsignedByteArray value, final KeyType keyType) { + return new PrivateKey(value, keyType); // <-- rely on constructor for all validation and error messaging. + } + + /** + * Instantiates a new instance of {@link PrivateKey} using the supplied bytes by inspecting the first byte out of 33 + * to see which {@link KeyType} to assign. + * + * @param value An {@link UnsignedByteArray} containing a private key's natural bytes (i.e., 32 bytes). + * + * @return A {@link PrivateKey}. + */ + public static PrivateKey fromPrefixedBytes(final UnsignedByteArray value) { Objects.requireNonNull(value); - final UnsignedByte firstByte = value.get(0); - Preconditions.checkArgument( - value.length() == 33 && (ED2559_PREFIX.equals(firstByte) || SECP256K1_PREFIX.equals(firstByte)), - "Constructing a PrivateKey with raw bytes requires a one-byte prefix in front of the 32 natural " + - "bytes of a private key. Use the prefix `0xED` for ed25519 private keys, or `0x00` for secp256k1 private keys." - ); + Preconditions.checkArgument(value.length() == 33, CONSTRUCTOR_ERROR_MESSAGE); - return new PrivateKey(value); + final UnsignedByte prefixByte = value.get(0); // <-- relies upon the above length check. + if (ED2559_PREFIX.equals(prefixByte)) { + return new PrivateKey(value.slice(1, 33), KeyType.ED25519); + } else if (SECP256K1_PREFIX.equals(prefixByte)) { + return new PrivateKey(value.slice(1, 33), KeyType.SECP256K1); + } else { + throw new IllegalArgumentException(CONSTRUCTOR_ERROR_MESSAGE); + } + } + + /** + * Instantiates a new instance of {@link PrivateKey} using the supplied bytes by inspecting the first byte out of 33 + * to see which {@link KeyType} to assign. + * + * @param value An {@link UnsignedByteArray} containing this key's binary value. + * + * @return A {@link PrivateKey}. + * + * @deprecated This method will be removed in a future version. Prefer {@link #fromPrefixedBytes(UnsignedByteArray)} + * instead. + */ + @Deprecated + public static PrivateKey of(final UnsignedByteArray value) { + return fromPrefixedBytes(value); } /** @@ -87,16 +127,49 @@ public static PrivateKey of(final UnsignedByteArray value) { * * @param value An {@link UnsignedByteArray} for this key's value. */ - private PrivateKey(final UnsignedByteArray value) { + private PrivateKey(final UnsignedByteArray value, final KeyType keyType) { this.value = Objects.requireNonNull(value); + this.keyType = Objects.requireNonNull(keyType); + + // We assert this precondition here instead of allowing 33 bytes because this is a private constructor that can be + // fully tested via unit test, so this precondition should never be violated, and if it is, then it's a bug in + // xrpl4j. + Preconditions.checkArgument( + value.length() == 32, + "Byte values passed to this constructor must be 32 bytes long, with no prefix." + ); } /** * Accessor for the key value, in binary (Note: will be 33 bytes). * * @return An instance of {@link UnsignedByteArray}. + * + * @deprecated Prefer {@link #valueWithPrefixedBytes()} or {@link #valueWithNaturalBytes()} instead. */ + @Deprecated public UnsignedByteArray value() { + // This is technically wrong (because `value()` had an ambiguous meaning prior to fixing #486), but this mirrors + // what's in v3 prior to fixing #486, and will be fixed in v4 once the deprecated `.value()` is removed. + if (value.length() == 0) { + return UnsignedByteArray.empty(); + } else { + + return this.valueWithPrefixedBytes(); + } + } + + /** + * Accessor for the byte value in {@link #value()} but in a more natural form (i.e., the size of the returned value + * will be 32 bytes). Natural ed25519 or secp256k1 private keys will ordinarily contain only 32 bytes. However, in + * XRPL, private keys are represented with a single-byte prefix (i.e., `0xED` for ed25519 and `0x00` for secp256k1 + * keys). + * + * @return An instance of {@link UnsignedByteArray}. + */ + public UnsignedByteArray valueWithNaturalBytes() { + // Note: `toByteArray()` will perform a copy, which is what we want in order to enforce immutability of this + // PrivateKey (because Java 8 doesn't support immutable byte arrays). return UnsignedByteArray.of(value.toByteArray()); } @@ -108,11 +181,21 @@ public UnsignedByteArray value() { * * @return An instance of {@link UnsignedByteArray}. */ - public UnsignedByteArray valueWithoutPrefix() { + public UnsignedByteArray valueWithPrefixedBytes() { // Note: value.slice() will take a view of the existing UBA, then `.toByteArray()` will perform a copy, which is // what we want in order to enforce immutability of this PrivateKey (because Java 8 doesn't support immutable byte // arrays). - return UnsignedByteArray.of(value.slice(1, 33).toByteArray()); + switch (keyType) { + case ED25519: { + return UnsignedByteArray.of(ED2559_PREFIX).append(value); + } + case SECP256K1: { + return UnsignedByteArray.of(SECP256K1_PREFIX).append(value); + } + default: { + throw new IllegalStateException(String.format("Invalid keyType=%s", keyType)); + } + } } /** @@ -121,14 +204,7 @@ public UnsignedByteArray valueWithoutPrefix() { * @return A {@link KeyType}. */ public final KeyType keyType() { - final UnsignedByte prefixByte = this.value().get(0); - if (ED2559_PREFIX.equals(prefixByte)) { - return KeyType.ED25519; - } else if (SECP256K1_PREFIX.equals(prefixByte)) { - return KeyType.SECP256K1; - } else { - throw new IllegalStateException("Prefix may only be 0xED or 0x00"); - } + return this.keyType; } @Override @@ -147,25 +223,25 @@ public boolean equals(Object obj) { if (this == obj) { return true; } - if (!(obj instanceof PrivateKey)) { + if (obj == null || getClass() != obj.getClass()) { return false; } - PrivateKey that = (PrivateKey) obj; - - return value.equals(that.value); + return Objects.equals(value, that.value) && keyType == that.keyType; } @Override public int hashCode() { - return value.hashCode(); + return Objects.hash(value, keyType); } @Override public String toString() { - return "PrivateKey{" + - "value=[redacted]" + - ", destroyed=" + destroyed + - '}'; + return String.format("PrivateKey{" + + "value=[redacted]," + + "keyType=%s," + + "destroyed=%s" + + "}", this.keyType(), this.isDestroyed() + ); } } diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/addresses/PrivateKeyCodecTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/addresses/PrivateKeyCodecTest.java new file mode 100644 index 000000000..a925c330f --- /dev/null +++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/codec/addresses/PrivateKeyCodecTest.java @@ -0,0 +1,90 @@ +package org.xrpl.xrpl4j.codec.addresses; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.xrpl.xrpl4j.crypto.TestConstants; +import org.xrpl.xrpl4j.crypto.keys.Passphrase; +import org.xrpl.xrpl4j.crypto.keys.Seed; + +/** + * Unit tests for {@link PrivateKeyCodec}. + */ +class PrivateKeyCodecTest extends AbstractCodecTest { + + private PrivateKeyCodec privateKeyCodec; + + @BeforeEach + void setUp() { + privateKeyCodec = PrivateKeyCodec.getInstance(); + } + + @Test + public void encodeDecodeEdNodePrivate() { + testEncodeDecode( + prefixedNodePrivateKey -> privateKeyCodec.encodeNodePrivateKey(prefixedNodePrivateKey), + prefixedNodePrivateKey -> privateKeyCodec.decodeNodePrivateKey(prefixedNodePrivateKey), + TestConstants.ED_PRIVATE_KEY.valueWithNaturalBytes(), + "paZHnTCvwm4GsxZ7qiA2nUBKE2DLnCoDWYqyocVZfVEZx3kvA4u" + ); + } + + /** + * These values come from the rippled codebase in Seed_test.cpp. + */ + @Test + public void encodeDecodeNodePrivateFromRippled() { + Seed seed = Seed.ed25519SeedFromPassphrase(Passphrase.of("masterpassphrase")); + + testEncodeDecode( + prefixedNodePrivateKey -> privateKeyCodec.encodeNodePrivateKey(prefixedNodePrivateKey), + prefixedNodePrivateKey -> privateKeyCodec.decodeNodePrivateKey(prefixedNodePrivateKey), + seed.deriveKeyPair().privateKey().valueWithNaturalBytes(), + "paKv46LztLqK3GaKz1rG2nQGN6M4JLyRtxFBYFTw4wAVHtGys36" + ); + } + + @Test + public void encodeDecodeEdAccountPrivateKey() { + testEncodeDecode( + prefixedAccountPrivateKey -> privateKeyCodec.encodeAccountPrivateKey(prefixedAccountPrivateKey), + prefixedAccountPrivateKey -> privateKeyCodec.decodeAccountPrivateKey(prefixedAccountPrivateKey), + TestConstants.ED_PRIVATE_KEY.valueWithNaturalBytes(), + "pwSmRvZy1c55Kb5tCpBZyq41noSmPn7ynFzUHu1MaoGLAP1VfrT" + ); + } + + /** + * These values come from the rippled codebase in Seed_test.cpp. + */ + @Test + public void encodeDecodeAccountPrivateKeyFromRippled() { + Seed seed = Seed.secp256k1SeedFromPassphrase(Passphrase.of("masterpassphrase")); + + testEncodeDecode( + prefixedNodePrivateKey -> privateKeyCodec.encodeAccountPrivateKey(prefixedNodePrivateKey), + prefixedNodePrivateKey -> privateKeyCodec.decodeAccountPrivateKey(prefixedNodePrivateKey), + seed.deriveKeyPair().privateKey().valueWithNaturalBytes(), + "p9JfM6HHi64m6mvB6v5k7G2b1cXzGmYiCNJf6GHPKvFTWdeRVjh" + ); + } + + @Test + public void encodeDecodeEcNodePrivate() { + testEncodeDecode( + prefixedNodePrivate -> privateKeyCodec.encodeNodePrivateKey(prefixedNodePrivate), + prefixedNodePrivate -> privateKeyCodec.decodeNodePrivateKey(prefixedNodePrivate), + TestConstants.EC_PRIVATE_KEY.valueWithNaturalBytes(), + "pa1UHARsPMiuDqrJLwFhzcJokoHgyiuaxgPhUGYhkG5ArCfG2vt" + ); + } + + @Test + public void encodeDecodeEcAccountPrivateKey() { + testEncodeDecode( + prefixedAccountPrivateKey -> privateKeyCodec.encodeAccountPrivateKey(prefixedAccountPrivateKey), + prefixedNodePrivateKey -> privateKeyCodec.decodeAccountPrivateKey(prefixedNodePrivateKey), + TestConstants.EC_PRIVATE_KEY.valueWithNaturalBytes(), + "pwkgeQKfaDDMV7w59LhhuEWMbpX3HG2iXxXGgZuij2j6z1RYY7n" + ); + } +} \ No newline at end of file diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/TestConstants.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/TestConstants.java index 2abd02fb5..746b856e6 100644 --- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/TestConstants.java +++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/TestConstants.java @@ -9,9 +9,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,6 +21,7 @@ */ import com.google.common.io.BaseEncoding; +import org.xrpl.xrpl4j.codec.addresses.KeyType; import org.xrpl.xrpl4j.codec.addresses.UnsignedByteArray; import org.xrpl.xrpl4j.crypto.keys.PrivateKey; import org.xrpl.xrpl4j.crypto.keys.PublicKey; @@ -36,18 +37,26 @@ public interface TestConstants { String ED_PUBLIC_KEY_B58 = "aKEusmsH9dJvjfeEg8XhDfpEgmhcK1epAtFJfAQbACndz5mUA73B"; PublicKey ED_PUBLIC_KEY = PublicKey.fromBase16EncodedPublicKey(ED_PUBLIC_KEY_HEX); - String ED_PRIVATE_KEY_HEX = "EDB224AFDCCEC7AA4E245E35452585D4FBBE37519BCA3929578BFC5BBD4640E163"; - String ED_PRIVATE_KEY_B58 = "pDcQTi2uFBAzQ7cY2mYQtk9QuQBoLU6rJypEf8EYPQoouh"; - PrivateKey ED_PRIVATE_KEY = PrivateKey.of(UnsignedByteArray.of(BaseEncoding.base16().decode(ED_PRIVATE_KEY_HEX))); + String ED_PRIVATE_KEY_HEX = "B224AFDCCEC7AA4E245E35452585D4FBBE37519BCA3929578BFC5BBD4640E163"; + String ED_PRIVATE_KEY_WITH_PREFIX_HEX = "ED" + ED_PRIVATE_KEY_HEX; + String ED_PRIVATE_KEY_B58 = "UzQrAxCr8oeMRzzm6FFVJao8xkFc3g2ZQBs5GNBWRhZg"; + PrivateKey ED_PRIVATE_KEY = PrivateKey.fromNaturalBytes( + UnsignedByteArray.of(BaseEncoding.base16().decode(ED_PRIVATE_KEY_HEX)), + KeyType.ED25519 + ); // Secp256k1 Public Key String EC_PUBLIC_KEY_HEX = "027535A4E90B2189CF9885563F45C4F454B3BFAB21930089C3878A9427B4D648D9"; String EC_PUBLIC_KEY_B58 = "aB4ifx88a26RYRSSzeKW8HpbXfbpzQFRsX6dMNmMwEVHUTKzfWdk"; PublicKey EC_PUBLIC_KEY = PublicKey.fromBase16EncodedPublicKey(EC_PUBLIC_KEY_HEX); - String EC_PRIVATE_KEY_HEX = "00DAD3C2B4BF921398932C889DE5335F89D90249355FC6FFB73F1256D2957F9F17"; - String EC_PRIVATE_KEY_B58 = "rEjDwJp2Pm3NrUtcf8v17jWopvqPJxyi5RTrDfhcJcWSi"; - PrivateKey EC_PRIVATE_KEY = PrivateKey.of(UnsignedByteArray.of(BaseEncoding.base16().decode(EC_PRIVATE_KEY_HEX))); + String EC_PRIVATE_KEY_HEX = "DAD3C2B4BF921398932C889DE5335F89D90249355FC6FFB73F1256D2957F9F17"; + String EC_PRIVATE_KEY_WITH_PREFIX_HEX = "00" + EC_PRIVATE_KEY_HEX; + String EC_PRIVATE_KEY_WITH_PREFIX_B58 = "rEjDwJp2Pm3NrUtcf8v17jWopvqPJxyi5RTrDfhcJcWSi"; + + PrivateKey EC_PRIVATE_KEY = PrivateKey.fromNaturalBytes( + UnsignedByteArray.of(BaseEncoding.base16().decode(EC_PRIVATE_KEY_HEX)), KeyType.SECP256K1 + ); // Both generated from Passphrase.of("hello") Address ED_ADDRESS = Address.of("rwGWYtRR6jJJJq7FKQg74YwtkiPyUqJ466"); diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/keys/PrivateKeyTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/keys/PrivateKeyTest.java index 5b4cbec5a..d0f51a8a0 100644 --- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/keys/PrivateKeyTest.java +++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/keys/PrivateKeyTest.java @@ -24,34 +24,40 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.xrpl.xrpl4j.crypto.TestConstants.EC_PRIVATE_KEY; import static org.xrpl.xrpl4j.crypto.TestConstants.EC_PRIVATE_KEY_HEX; +import static org.xrpl.xrpl4j.crypto.TestConstants.EC_PRIVATE_KEY_WITH_PREFIX_HEX; import static org.xrpl.xrpl4j.crypto.TestConstants.ED_PRIVATE_KEY; import static org.xrpl.xrpl4j.crypto.TestConstants.ED_PRIVATE_KEY_HEX; +import static org.xrpl.xrpl4j.crypto.TestConstants.ED_PRIVATE_KEY_WITH_PREFIX_HEX; import com.google.common.io.BaseEncoding; import org.junit.jupiter.api.Test; -import org.xrpl.xrpl4j.codec.addresses.Base58; import org.xrpl.xrpl4j.codec.addresses.KeyType; import org.xrpl.xrpl4j.codec.addresses.UnsignedByteArray; -import org.xrpl.xrpl4j.crypto.TestConstants; /** * Unit tests for {@link PrivateKey}. */ +@SuppressWarnings("deprecation") class PrivateKeyTest { - @Test - void testOfWithNull() { - assertThrows(NullPointerException.class, () -> PrivateKey.of(null)); - } - private static final String EXPECTED_ERROR = "Constructing a PrivateKey with raw bytes requires a one-byte prefix in front of the 32 natural" + " bytes of a private key. Use the prefix `0xED` for ed25519 private keys, or `0x00` for secp256k1 private " + "keys."; + //////////////////// + // of + //////////////////// + @Test - void testEcOfWithOnly32Bytes() { - UnsignedByteArray thirtyThreeBytes = UnsignedByteArray.of(BaseEncoding.base16().decode(EC_PRIVATE_KEY_HEX)); + void testOfWithNull() { + assertThrows(NullPointerException.class, () -> PrivateKey.of(null)); + } + + @Test + void testEcOf() { + UnsignedByteArray thirtyThreeBytes = UnsignedByteArray.of( + BaseEncoding.base16().decode(EC_PRIVATE_KEY_WITH_PREFIX_HEX)); assertThat(PrivateKey.of(thirtyThreeBytes)).isEqualTo(EC_PRIVATE_KEY); UnsignedByteArray thirtyTwoBytes = UnsignedByteArray.of(thirtyThreeBytes.slice(1, 33).toByteArray()); @@ -62,17 +68,9 @@ void testEcOfWithOnly32Bytes() { } @Test - void testConstants() { - assertThat(PrivateKey.ED2559_PREFIX.asInt()).isEqualTo(0xED); - assertThat(PrivateKey.ED2559_PREFIX.asByte()).isEqualTo((byte) 0xED); - - assertThat(PrivateKey.SECP256K1_PREFIX.asInt()).isEqualTo(0x00); - assertThat(PrivateKey.SECP256K1_PREFIX.asByte()).isEqualTo((byte) 0x00); - } - - @Test - void testEdOfWithOnly32Bytes() { - UnsignedByteArray thirtyThreeBytes = UnsignedByteArray.of(BaseEncoding.base16().decode(ED_PRIVATE_KEY_HEX)); + void testEdOf() { + UnsignedByteArray thirtyThreeBytes = UnsignedByteArray.of( + BaseEncoding.base16().decode(ED_PRIVATE_KEY_WITH_PREFIX_HEX)); assertThat(PrivateKey.of(thirtyThreeBytes)).isEqualTo(ED_PRIVATE_KEY); UnsignedByteArray thirtyTwoBytes = UnsignedByteArray.of(thirtyThreeBytes.slice(1, 33).toByteArray()); @@ -100,36 +98,153 @@ void testEcOfWithLessThan32Bytes() { assertThat(exception.getMessage()).isEqualTo(EXPECTED_ERROR); } + /////////////////// + // fromNaturalBytes + /////////////////// + @Test - void valueEd25519() { - assertThat(Base58.encode(ED_PRIVATE_KEY.value().toByteArray())).isEqualTo(TestConstants.ED_PRIVATE_KEY_B58); + void testFromNaturalBytesWithNull() { + assertThrows(NullPointerException.class, () -> PrivateKey.fromNaturalBytes(null, KeyType.ED25519)); + assertThrows(NullPointerException.class, () -> PrivateKey.fromNaturalBytes(UnsignedByteArray.empty(), null)); } @Test - void valueSecp256k1() { - assertThat(Base58.encode(EC_PRIVATE_KEY.value().toByteArray())).isEqualTo(TestConstants.EC_PRIVATE_KEY_B58); + void testEcFromNaturalBytes() { + UnsignedByteArray thirtyThreeBytes = UnsignedByteArray.of( + BaseEncoding.base16().decode(EC_PRIVATE_KEY_WITH_PREFIX_HEX)); + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, () -> PrivateKey.fromNaturalBytes(thirtyThreeBytes, KeyType.SECP256K1) + ); + assertThat(exception.getMessage()) + .isEqualTo("Byte values passed to this constructor must be 32 bytes long, with no prefix."); + + UnsignedByteArray thirtyTwoBytes = UnsignedByteArray.of(thirtyThreeBytes.slice(1, 33).toByteArray()); + assertThat(PrivateKey.fromNaturalBytes(thirtyTwoBytes, KeyType.SECP256K1)).isEqualTo(EC_PRIVATE_KEY); + } + + @Test + void testEdFromNaturalBytes() { + UnsignedByteArray thirtyThreeBytes = UnsignedByteArray.of( + BaseEncoding.base16().decode(ED_PRIVATE_KEY_WITH_PREFIX_HEX)); + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, () -> PrivateKey.fromNaturalBytes(thirtyThreeBytes, KeyType.ED25519) + ); + assertThat(exception.getMessage()) + .isEqualTo("Byte values passed to this constructor must be 32 bytes long, with no prefix."); + + UnsignedByteArray thirtyTwoBytes = UnsignedByteArray.of(thirtyThreeBytes.slice(1, 33).toByteArray()); + assertThat(PrivateKey.fromNaturalBytes(thirtyTwoBytes, KeyType.ED25519)).isEqualTo(ED_PRIVATE_KEY); + } + + @Test + void testEdFromNaturalBytesWithLessThan32Bytes() { + UnsignedByteArray twoBytes = UnsignedByteArray.of(new byte[] {(byte) 0xED, (byte) 0xFF}); + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, () -> PrivateKey.fromNaturalBytes(twoBytes, KeyType.ED25519) + ); + assertThat(exception.getMessage()) + .isEqualTo("Byte values passed to this constructor must be 32 bytes long, with no prefix."); } @Test - void valueWithoutPrefixEd25519() { - UnsignedByteArray expectedValueWithoutPrefix = UnsignedByteArray.of( - BaseEncoding.base16().decode(ED_PRIVATE_KEY_HEX)).slice(1, 33); - assertThat(expectedValueWithoutPrefix.length()).isEqualTo(32); + void testEcFromNaturalBytesWithLessThan32Bytes() { + UnsignedByteArray twoBytes = UnsignedByteArray.of(new byte[] {(byte) 0x00, (byte) 0xFF}); + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, () -> PrivateKey.fromNaturalBytes(twoBytes, KeyType.SECP256K1) + ); + assertThat(exception.getMessage()) + .isEqualTo("Byte values passed to this constructor must be 32 bytes long, with no prefix."); + } + + //////////////////// + // fromPrefixedBytes + //////////////////// - assertThat(ED_PRIVATE_KEY.value().slice(1, 33)).isEqualTo(expectedValueWithoutPrefix); - assertThat(ED_PRIVATE_KEY.valueWithoutPrefix()).isEqualTo(expectedValueWithoutPrefix); + @Test + void testFromPrefixedBytesWithNull() { + assertThrows(NullPointerException.class, () -> PrivateKey.fromPrefixedBytes(null)); } @Test - void valueWithoutPrefixSecp256k1() { - UnsignedByteArray expectedValueWithoutPrefix = UnsignedByteArray.of( - BaseEncoding.base16().decode(EC_PRIVATE_KEY_HEX)).slice(1, 33); - assertThat(expectedValueWithoutPrefix.length()).isEqualTo(32); + void testEcFromPrefixedBytes() { + UnsignedByteArray thirtyThreeBytes = UnsignedByteArray.of( + BaseEncoding.base16().decode(EC_PRIVATE_KEY_WITH_PREFIX_HEX) + ); + assertThat(PrivateKey.fromPrefixedBytes(thirtyThreeBytes)).isEqualTo(EC_PRIVATE_KEY); - assertThat(EC_PRIVATE_KEY.value().slice(1, 33)).isEqualTo(expectedValueWithoutPrefix); - assertThat(EC_PRIVATE_KEY.valueWithoutPrefix()).isEqualTo(expectedValueWithoutPrefix); + UnsignedByteArray thirtyTwoBytes = UnsignedByteArray.of(thirtyThreeBytes.slice(1, 33).toByteArray()); + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, () -> PrivateKey.fromPrefixedBytes(thirtyTwoBytes) + ); + assertThat(exception.getMessage()).isEqualTo(EXPECTED_ERROR); + } + + @Test + void testEdFromPrefixedBytes() { + UnsignedByteArray thirtyThreeBytes = UnsignedByteArray.of( + BaseEncoding.base16().decode(ED_PRIVATE_KEY_WITH_PREFIX_HEX) + ); + assertThat(PrivateKey.fromPrefixedBytes(thirtyThreeBytes)).isEqualTo(ED_PRIVATE_KEY); + + UnsignedByteArray thirtyTwoBytes = UnsignedByteArray.of(thirtyThreeBytes.slice(1, 33).toByteArray()); + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, () -> PrivateKey.fromPrefixedBytes(thirtyTwoBytes) + ); + assertThat(exception.getMessage()).isEqualTo(EXPECTED_ERROR); + } + + @Test + void testEdFromPrefixedBytesWithLessThan32Bytes() { + UnsignedByteArray twoBytes = UnsignedByteArray.of(new byte[] {(byte) 0xED, (byte) 0xFF}); + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, () -> PrivateKey.fromPrefixedBytes(twoBytes) + ); + assertThat(exception.getMessage()).isEqualTo(EXPECTED_ERROR); + } + + @Test + void testEcFromPrefixedBytesWithLessThan32Bytes() { + UnsignedByteArray twoBytes = UnsignedByteArray.of(new byte[] {(byte) 0x00, (byte) 0xFF}); + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, () -> PrivateKey.fromPrefixedBytes(twoBytes) + ); + assertThat(exception.getMessage()).isEqualTo(EXPECTED_ERROR); + } + + /////////////////// + // Constants + /////////////////// + + @Test + void testConstants() { + assertThat(PrivateKey.ED2559_PREFIX.asInt()).isEqualTo(0xED); + assertThat(PrivateKey.ED2559_PREFIX.asByte()).isEqualTo((byte) 0xED); + + assertThat(PrivateKey.SECP256K1_PREFIX.asInt()).isEqualTo(0x00); + assertThat(PrivateKey.SECP256K1_PREFIX.asByte()).isEqualTo((byte) 0x00); + } + + /////////////////// + // value tests ==> [value, valueWithPrefixedBytes, valueWithNaturalBytes] + /////////////////// + + @Test + void valueForEd25519() { + assertThat(ED_PRIVATE_KEY.value().hexValue()).isEqualTo(ED_PRIVATE_KEY_WITH_PREFIX_HEX); + assertThat(ED_PRIVATE_KEY.valueWithPrefixedBytes().hexValue()).isEqualTo(ED_PRIVATE_KEY_WITH_PREFIX_HEX); + assertThat(ED_PRIVATE_KEY.valueWithNaturalBytes().hexValue()).isEqualTo(ED_PRIVATE_KEY_HEX); + } + + @Test + void valueForSecp256k1() { + assertThat(EC_PRIVATE_KEY.value().hexValue()).isEqualTo(EC_PRIVATE_KEY_WITH_PREFIX_HEX); + assertThat(EC_PRIVATE_KEY.valueWithPrefixedBytes().hexValue()).isEqualTo(EC_PRIVATE_KEY_WITH_PREFIX_HEX); + assertThat(EC_PRIVATE_KEY.valueWithNaturalBytes().hexValue()).isEqualTo(EC_PRIVATE_KEY_HEX); } + /////////////////// + // Misc + /////////////////// @Test void keyTypeEd25519() { @@ -188,14 +303,16 @@ void testHashcode() { void testToString() { assertThat(ED_PRIVATE_KEY.toString()).isEqualTo( "PrivateKey{" + - "value=[redacted], " + + "value=[redacted]," + + "keyType=ED25519," + "destroyed=false" + "}" ); assertThat(EC_PRIVATE_KEY.toString()).isEqualTo( "PrivateKey{" + - "value=[redacted], " + + "value=[redacted]," + + "keyType=SECP256K1," + "destroyed=false" + "}" ); diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/keys/PublicKeyTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/keys/PublicKeyTest.java index ed9d9b304..c3d768492 100644 --- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/keys/PublicKeyTest.java +++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/keys/PublicKeyTest.java @@ -9,9 +9,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,6 +21,7 @@ */ import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.xrpl.xrpl4j.crypto.TestConstants.EC_PUBLIC_KEY; import static org.xrpl.xrpl4j.crypto.TestConstants.EC_PUBLIC_KEY_B58; import static org.xrpl.xrpl4j.crypto.TestConstants.EC_PUBLIC_KEY_HEX; @@ -32,6 +33,7 @@ import org.junit.jupiter.api.Test; import org.xrpl.xrpl4j.codec.addresses.KeyType; import org.xrpl.xrpl4j.codec.addresses.UnsignedByteArray; +import org.xrpl.xrpl4j.codec.addresses.exceptions.EncodeException; import org.xrpl.xrpl4j.model.jackson.ObjectMapperFactory; import org.xrpl.xrpl4j.model.transactions.Address; @@ -40,6 +42,15 @@ */ public class PublicKeyTest { + @Test + public void fromBase58EncodedStringEd25519WithTooFewBytes() { + UnsignedByteArray twoBytes = UnsignedByteArray.of(new byte[] {(byte) 0xED, (byte) 0xFF}); + EncodeException exception = assertThrows( + EncodeException.class, () -> PublicKey.fromBase16EncodedPublicKey(twoBytes.hexValue()) + ); + assertThat(exception.getMessage()).isEqualTo("Length of bytes does not match expectedLength of 33."); + } + @Test public void fromBase58EncodedStringEd25519() { assertThat(PublicKey.fromBase58EncodedPublicKey(ED_PUBLIC_KEY_B58).base58Value()).isEqualTo(ED_PUBLIC_KEY_B58); @@ -196,7 +207,7 @@ void jsonSerializeAndDeserializeMultiSignKey() throws JsonProcessingException { PublicKey actual = ObjectMapperFactory.create().readValue(json, PublicKey.class); assertThat(actual.base16Value()).isEqualTo(""); } - + @Test void jsonSerializeAndDeserializeEc() throws JsonProcessingException { String json = ObjectMapperFactory.create().writeValueAsString(EC_PUBLIC_KEY); diff --git a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/keys/SeedTest.java b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/keys/SeedTest.java index 56bc5a578..1b60c83c6 100644 --- a/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/keys/SeedTest.java +++ b/xrpl4j-core/src/test/java/org/xrpl/xrpl4j/crypto/keys/SeedTest.java @@ -27,16 +27,8 @@ import org.junit.jupiter.api.Test; import org.xrpl.xrpl4j.codec.addresses.Base58; import org.xrpl.xrpl4j.codec.addresses.KeyType; -import org.xrpl.xrpl4j.codec.addresses.SeedCodec; import org.xrpl.xrpl4j.codec.addresses.UnsignedByteArray; import org.xrpl.xrpl4j.codec.addresses.exceptions.DecodeException; -import org.xrpl.xrpl4j.crypto.keys.Base58EncodedSecret; -import org.xrpl.xrpl4j.crypto.keys.Entropy; -import org.xrpl.xrpl4j.crypto.keys.KeyPair; -import org.xrpl.xrpl4j.crypto.keys.Passphrase; -import org.xrpl.xrpl4j.crypto.keys.PrivateKey; -import org.xrpl.xrpl4j.crypto.keys.PublicKey; -import org.xrpl.xrpl4j.crypto.keys.Seed; import org.xrpl.xrpl4j.crypto.keys.Seed.DefaultSeed; import javax.security.auth.DestroyFailedException; @@ -44,10 +36,11 @@ /** * Unit tests for {@link Seed}. */ +@SuppressWarnings("deprecation") public class SeedTest { - private Seed edSeed = Seed.ed25519SeedFromPassphrase(Passphrase.of("hello")); - private Seed ecSeed = Seed.secp256k1SeedFromPassphrase(Passphrase.of("hello")); + private final Seed edSeed = Seed.ed25519SeedFromPassphrase(Passphrase.of("hello")); + private final Seed ecSeed = Seed.secp256k1SeedFromPassphrase(Passphrase.of("hello")); @Test void constructorWithNullSeed() { @@ -59,10 +52,7 @@ void constructorWithNullSeed() { @Test void constructorWithNullUnsignedByteArray() { - assertThrows(NullPointerException.class, () -> { - UnsignedByteArray nullUba = null; - new DefaultSeed(nullUba); - }); + assertThrows(NullPointerException.class, () -> new DefaultSeed((UnsignedByteArray) null)); } @Test @@ -127,6 +117,7 @@ void testSecp256k1SeedFromPassphraseWithNull() { @Test public void testEd25519SeedFromPassphrase() throws DestroyFailedException { + //noinspection OptionalGetWithoutIsPresent assertThat(edSeed.decodedSeed().type().get()).isEqualTo(KeyType.ED25519); assertThat(BaseEncoding.base64().encode(edSeed.decodedSeed().bytes().toByteArray())) .isEqualTo("m3HSJL1i83hdltRq0+o9cw=="); @@ -137,6 +128,7 @@ public void testEd25519SeedFromPassphrase() throws DestroyFailedException { @Test public void testSecp256k1SeedFromPassphrase() throws DestroyFailedException { + //noinspection OptionalGetWithoutIsPresent assertThat(ecSeed.decodedSeed().type().get()).isEqualTo(KeyType.SECP256K1); assertThat(BaseEncoding.base64().encode(ecSeed.decodedSeed().bytes().toByteArray())) .isEqualTo("m3HSJL1i83hdltRq0+o9cw=="); @@ -181,7 +173,9 @@ void deriveKeyPairFor32ByteEcSeed() { final PrivateKey privateKey = ecSeedFor32BytePrivateKey.deriveKeyPair().privateKey(); assertThat(privateKey.value().hexValue()) .isEqualTo("007030CBD40D6961E625AD73159A4B463AA42B4E88CC2248AC49E1EDCB50AF2924"); - assertThat(privateKey.valueWithoutPrefix().hexValue()) + assertThat(privateKey.valueWithPrefixedBytes().hexValue()) + .isEqualTo("007030CBD40D6961E625AD73159A4B463AA42B4E88CC2248AC49E1EDCB50AF2924"); + assertThat(privateKey.valueWithNaturalBytes().hexValue()) .isEqualTo("7030CBD40D6961E625AD73159A4B463AA42B4E88CC2248AC49E1EDCB50AF2924"); } @@ -202,14 +196,16 @@ void deriveKeyPairFor33ByteEcSeed() { final PrivateKey privateKey = ecSeedFor32BytePrivateKey.deriveKeyPair().privateKey(); assertThat(privateKey.value().hexValue()) .isEqualTo("00FBD60C9C99BA3D4706A449C30E4D61DCC3811E23EF69291F98A886CEC6A8B0B5"); - assertThat(privateKey.valueWithoutPrefix().hexValue()) + assertThat(privateKey.valueWithPrefixedBytes().hexValue()) + .isEqualTo("00FBD60C9C99BA3D4706A449C30E4D61DCC3811E23EF69291F98A886CEC6A8B0B5"); + assertThat(privateKey.valueWithNaturalBytes().hexValue()) .isEqualTo("FBD60C9C99BA3D4706A449C30E4D61DCC3811E23EF69291F98A886CEC6A8B0B5"); } @Test void testEquals() { - assertThat(edSeed).isEqualTo(edSeed); - assertThat(ecSeed).isEqualTo(ecSeed); + assertThat(edSeed.equals(edSeed)).isTrue(); + assertThat(ecSeed.equals(ecSeed)).isTrue(); assertThat(edSeed).isNotEqualTo(ecSeed); assertThat(ecSeed).isNotEqualTo(edSeed); assertThat(ecSeed).isNotEqualTo(new Object());