mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-01-31 23:32:16 +00:00
Add optional support native ECDSA (designed for sipa's impl).
This could be significantly more optimized if we avoided crossing the JNI barrier as often, but as it is its waaay faster than BouncyCastle.
This commit is contained in:
parent
70bffcd6f4
commit
59e096e2ea
@ -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.
|
||||
* <p>xVerifies the given ECDSA signature against the message bytes using the public key bytes.</p>
|
||||
*
|
||||
* <p>When using native ECDSA verification, data must be 32 bytes, and no element may be
|
||||
* larger than 520 bytes.</p>
|
||||
*
|
||||
* @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();
|
||||
|
78
core/src/main/java/org/bitcoin/NativeSecp256k1.java
Normal file
78
core/src/main/java/org/bitcoin/NativeSecp256k1.java
Normal file
@ -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;
|
||||
|
||||
|
||||
/**
|
||||
* <p>This class holds native methods to handle ECDSA verification.</p>
|
||||
*
|
||||
* <p>You can find an example library that can be used for this at https://github.com/sipa/secp256k1</p>
|
||||
*
|
||||
* <p>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
|
||||
* </p>
|
||||
*/
|
||||
public class NativeSecp256k1 {
|
||||
public static boolean enabled = true;
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("javasecp256k1");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
|
||||
/**
|
||||
* Verifies the given secp256k1 signature in native code.
|
||||
* Calling when enabled == false is undefined (probably library not loaded)
|
||||
*
|
||||
* @param data The data which was signed, must be exactly 32 bytes
|
||||
* @param signature The signature
|
||||
* @param pub The public key which did the signing
|
||||
*/
|
||||
public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
|
||||
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null) {
|
||||
byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(data);
|
||||
byteBuff.putInt(signature.length);
|
||||
byteBuff.putInt(pub.length);
|
||||
byteBuff.put(signature);
|
||||
byteBuff.put(pub);
|
||||
return secp256k1_ecdsa_verify(byteBuff) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param byteBuff signature format is byte[32] data,
|
||||
* native-endian int signatureLength, native-endian int pubkeyLength,
|
||||
* byte[signatureLength] signature, byte[pubkeyLength] pub
|
||||
* @returns 1 for valid signature, anything else for invalid
|
||||
*/
|
||||
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff);
|
||||
}
|
Loading…
Reference in New Issue
Block a user