Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

secp-api, secp-bouncy: compile as Java 9 #87

Merged
merged 2 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion secp-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
}

tasks.withType(JavaCompile).configureEach {
options.release = 17
options.release = 9
}

ext.moduleName = 'org.bitcoinj.secp.api'
Expand Down
1 change: 1 addition & 0 deletions secp-api/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
requires org.jspecify;

exports org.bitcoinj.secp.api;
exports org.bitcoinj.secp.api.internal; /* TEMPORARY */

uses org.bitcoinj.secp.api.Secp256k1Provider;
}
60 changes: 60 additions & 0 deletions secp-api/src/main/java/org/bitcoinj/secp/api/ByteArray.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2023-2024 secp256k1-jdk Developers.
*
* 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.
*/
package org.bitcoinj.secp.api;

import org.bitcoinj.secp.api.internal.ByteUtils;
import org.bitcoinj.secp.api.internal.HexFormat;

import java.util.Arrays;

/**
* An effectively-immutable byte array.
*/
public interface ByteArray extends Comparable<ByteArray> {
HexFormat HEX_FORMAT = new HexFormat();

/**
* @return the bytes as an array
*/
byte[] bytes();

/**
* @return the bytes as a hex-formatted string
*/
default String formatHex() {
return HEX_FORMAT.formatHex(bytes());
}

/**
* {@inheritDoc}
* <p>For {@link ByteArray} this is a byte-by-byte, unsigned comparison.
* @param o {@inheritDoc}
* @return {@inheritDoc}
*/
@Override
default int compareTo(ByteArray o) {
return ByteUtils.arrayUnsignedComparator().compare(bytes(), o.bytes());
}

/**
* Utility method to format hex bytes as string
* @param bytes bytes to format
* @return hex-formatted String
*/
static String toHexString(byte[] bytes) {
return HEX_FORMAT.formatHex(bytes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package org.bitcoinj.secp.api;

import java.math.BigInteger;
import java.util.HexFormat;

/**
*
Expand Down Expand Up @@ -56,7 +55,6 @@ static P256K1XOnlyPubKey of(BigInteger x) {
* Default implementation. Currently used by all known implementations
*/
class P256K1XOnlyPubKeyImpl implements P256K1XOnlyPubKey {
private static final HexFormat formatter = HexFormat.of();
private final BigInteger x;

public P256K1XOnlyPubKeyImpl(P256k1PubKey pubKey) {
Expand Down Expand Up @@ -86,7 +84,7 @@ public byte[] getSerialized() {
*/
@Override
public String toString() {
return formatter.formatHex(getSerialized());
return ByteArray.toHexString(getSerialized());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,11 @@
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.util.HexFormat;

/**
*
*/
public interface P256k1PubKey extends ECPublicKey {
HexFormat hf = HexFormat.of();

@Override
default String getAlgorithm() {
return "Secp256k1";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@
/**
*
*/
public interface SignatureData {
public byte[] bytes();
public interface SignatureData extends ByteArray {
byte[] bytes();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2023-2024 secp256k1-jdk Developers.
*
* 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.
*/
package org.bitcoinj.secp.api.internal;

import java.util.Comparator;

/**
*
*/
public class ByteUtils {
/**
* Provides a byte array comparator.
* @return A comparator for byte[]
*/
public static Comparator<byte[]> arrayUnsignedComparator() {
return ARRAY_UNSIGNED_COMPARATOR;
}

// In Java 9, this can be replaced with Arrays.compareUnsigned()
private static final Comparator<byte[]> ARRAY_UNSIGNED_COMPARATOR = (a, b) -> {
int minLength = Math.min(a.length, b.length);
for (int i = 0; i < minLength; i++) {
int result = compareUnsigned(a[i], b[i]);
if (result != 0) {
return result;
}
}
return a.length - b.length;
};

private static int compareUnsigned(byte a, byte b) {
return Byte.toUnsignedInt(a) - Byte.toUnsignedInt(b);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2023-2024 secp256k1-jdk Developers.
*
* 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.
*/

package org.bitcoinj.secp.api.internal;

/**
* This class implements a subset of the functionality of the {@code HexFormat} class available in Java 17 and later.
* Its behavior is the same as an instance of Java 17 {@code HexFormat} created with {@code HexFormat.of()}.
* It is an internal class and may be removed in the future when and if we have a Java 17 baseline. This is a copy of
* HexFormat.java in `bitcoinj-base/org.bitcoinj.base.internal`.
* <p>Thanks to this <a href="https://www.baeldung.com/java-byte-arrays-hex-strings">Baeldung article</a>.
*/
public class HexFormat {
public String formatHex(byte[] bytes) {
StringBuilder stringBuilder = new StringBuilder(bytes.length * 2);
for (byte aByte : bytes) {
stringBuilder.append(byteToHex(aByte));
}
return stringBuilder.toString();
}

public byte[] parseHex(String hexString) {
if (hexString.length() % 2 == 1) {
throw new IllegalArgumentException("Invalid hexadecimal String supplied.");
}

byte[] bytes = new byte[hexString.length() / 2];
for (int i = 0; i < hexString.length(); i += 2) {
bytes[i / 2] = hexToByte(hexString.substring(i, i + 2));
}
return bytes;
}
private String byteToHex(byte num) {
char[] hexDigits = new char[2];
hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16);
hexDigits[1] = Character.forDigit((num & 0xF), 16);
return new String(hexDigits);
}

private byte hexToByte(String hexString) {
int firstDigit = toDigit(hexString.charAt(0));
int secondDigit = toDigit(hexString.charAt(1));
return (byte) ((firstDigit << 4) + secondDigit);
}

private int toDigit(char hexChar) {
int digit = Character.digit(hexChar, 16);
if (digit == -1) {
throw new IllegalArgumentException("Invalid Hexadecimal Character: "+ hexChar);
}
return digit;
}
}
2 changes: 1 addition & 1 deletion secp-bouncy/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
}

tasks.withType(JavaCompile).configureEach {
options.release = 17
options.release = 9
}

ext.moduleName = 'org.bitcoinj.secp.bouncy'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.bitcoinj.secp.bouncy;


import org.bitcoinj.secp.api.ByteArray;
import org.bitcoinj.secp.api.P256k1PubKey;
import org.bouncycastle.math.ec.ECPoint;

Expand Down Expand Up @@ -49,7 +50,7 @@ public byte[] getEncoded() {

@Override
public String toString() {
return hf.formatHex(bytes()) ;
return ByteArray.HEX_FORMAT.formatHex(bytes());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.bitcoinj.secp.ffm;

import org.bitcoinj.secp.api.ByteArray;
import org.bitcoinj.secp.api.SignatureData;

import java.lang.foreign.MemorySegment;
Expand Down