diff --git a/core/src/main/java/com/google/bitcoin/core/ECKey.java b/core/src/main/java/com/google/bitcoin/core/ECKey.java index ebef9c59..9e275527 100644 --- a/core/src/main/java/com/google/bitcoin/core/ECKey.java +++ b/core/src/main/java/com/google/bitcoin/core/ECKey.java @@ -16,6 +16,7 @@ package com.google.bitcoin.core; +import org.bitcoin.NativeSecp256k1; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Preconditions; @@ -43,6 +44,8 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.Serializable; import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.nio.charset.Charset; import java.security.SecureRandom; import java.security.SignatureException; @@ -395,13 +398,19 @@ public class ECKey implements Serializable { } /** - * Verifies the given ECDSA signature against the message bytes using the public key bytes. + *
xVerifies the given ECDSA signature against the message bytes using the public key bytes.
+ * + *When using native ECDSA verification, data must be 32 bytes, and no element may be + * larger than 520 bytes.
* * @param data Hash of the data to verify. * @param signature ASN.1 encoded signature. * @param pub The public key bytes to use. */ public static boolean verify(byte[] data, ECDSASignature signature, byte[] pub) { + if (NativeSecp256k1.enabled) + return NativeSecp256k1.verify(data, signature.encodeToDER(), pub); + ECDSASigner signer = new ECDSASigner(); ECPublicKeyParameters params = new ECPublicKeyParameters(ecParams.getCurve().decodePoint(pub), ecParams); signer.init(false, params); @@ -424,6 +433,9 @@ public class ECKey implements Serializable { * @param pub The public key bytes to use. */ public static boolean verify(byte[] data, byte[] signature, byte[] pub) { + if (NativeSecp256k1.enabled) + return NativeSecp256k1.verify(data, signature, pub); + try { ASN1InputStream decoder = new ASN1InputStream(signature); DLSequence seq = (DLSequence) decoder.readObject(); diff --git a/core/src/main/java/org/bitcoin/NativeSecp256k1.java b/core/src/main/java/org/bitcoin/NativeSecp256k1.java new file mode 100644 index 00000000..de25ba43 --- /dev/null +++ b/core/src/main/java/org/bitcoin/NativeSecp256k1.java @@ -0,0 +1,78 @@ +/** + * Copyright 2013 Google Inc. + * + * 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.bitcoin; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import com.google.common.base.Preconditions; + + +/** + *This class holds native methods to handle ECDSA verification.
+ * + *You can find an example library that can be used for this at https://github.com/sipa/secp256k1
+ * + *To build secp256k1 for use with bitcoinj, run `./configure` and `make libjavasecp256k1.so` then copy + * libjavasecp256k1.so to your system library path or point the JVM to the folder containing it with -Djava.library.path + *
+ */ +public class NativeSecp256k1 { + public static boolean enabled = true; + static { + try { + System.loadLibrary("javasecp256k1"); + } catch (UnsatisfiedLinkError e) { + enabled = false; + } + } + + private static ThreadLocal