mirror of
https://github.com/sparrowwallet/drongo.git
synced 2024-11-05 03:26:43 +00:00
ensure grinding for low R is done in the same way as libsecp256k1 so signatures match
This commit is contained in:
parent
db05e09fe5
commit
173743ba0d
4 changed files with 28 additions and 22 deletions
|
@ -12,10 +12,6 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.nio.Buffer;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.CharBuffer;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
|
@ -115,6 +111,14 @@ public class Utils {
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void reverse(byte[] array) {
|
||||||
|
for (int i = 0; i < array.length / 2; i++) {
|
||||||
|
byte temp = array[i];
|
||||||
|
array[i] = array[array.length - i - 1];
|
||||||
|
array[array.length - i - 1] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Parse 4 bytes from the byte array (starting at the offset) as unsigned 32-bit integer in little endian format. */
|
/** Parse 4 bytes from the byte array (starting at the offset) as unsigned 32-bit integer in little endian format. */
|
||||||
public static long readUint32(byte[] bytes, int offset) {
|
public static long readUint32(byte[] bytes, int offset) {
|
||||||
return (bytes[offset] & 0xffl) |
|
return (bytes[offset] & 0xffl) |
|
||||||
|
|
|
@ -470,7 +470,8 @@ public class ECKey implements EncryptableItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean hasLowR() {
|
protected boolean hasLowR() {
|
||||||
return r.toByteArray().length <= 32;
|
//A low R signature will have less than 71 bytes when encoded to DER
|
||||||
|
return toCanonicalised().encodeToDER().length < 71;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -530,14 +531,14 @@ public class ECKey implements EncryptableItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
ECDSASignature signature;
|
ECDSASignature signature;
|
||||||
int counter = 0;
|
Integer counter = null;
|
||||||
do {
|
do {
|
||||||
ECDSASigner signer = new ECDSASigner(new HMacDSANonceKCalculator(new SHA256Digest(), counter));
|
ECDSASigner signer = new ECDSASigner(new HMacDSANonceKCalculator(new SHA256Digest(), counter));
|
||||||
ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(privateKeyForSigning, CURVE);
|
ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(privateKeyForSigning, CURVE);
|
||||||
signer.init(true, privKey);
|
signer.init(true, privKey);
|
||||||
BigInteger[] components = signer.generateSignature(input.getBytes());
|
BigInteger[] components = signer.generateSignature(input.getBytes());
|
||||||
signature = new ECDSASignature(components[0], components[1]).toCanonicalised();
|
signature = new ECDSASignature(components[0], components[1]).toCanonicalised();
|
||||||
counter++;
|
counter = (counter == null ? 1 : counter+1);
|
||||||
} while(!signature.hasLowR());
|
} while(!signature.hasLowR());
|
||||||
|
|
||||||
return signature;
|
return signature;
|
||||||
|
|
|
@ -21,7 +21,7 @@ public class HMacDSANonceKCalculator implements DSAKCalculator {
|
||||||
private final HMac hMac;
|
private final HMac hMac;
|
||||||
private final byte[] K;
|
private final byte[] K;
|
||||||
private final byte[] V;
|
private final byte[] V;
|
||||||
private final long counter;
|
private final Long counter;
|
||||||
|
|
||||||
private BigInteger n;
|
private BigInteger n;
|
||||||
|
|
||||||
|
@ -31,11 +31,11 @@ public class HMacDSANonceKCalculator implements DSAKCalculator {
|
||||||
* @param digest digest to build the HMAC on.
|
* @param digest digest to build the HMAC on.
|
||||||
* @param counter additional data as per RFC 6979 3.6
|
* @param counter additional data as per RFC 6979 3.6
|
||||||
*/
|
*/
|
||||||
public HMacDSANonceKCalculator(Digest digest, int counter) {
|
public HMacDSANonceKCalculator(Digest digest, Integer counter) {
|
||||||
this.hMac = new HMac(digest);
|
this.hMac = new HMac(digest);
|
||||||
this.V = new byte[hMac.getMacSize()];
|
this.V = new byte[hMac.getMacSize()];
|
||||||
this.K = new byte[hMac.getMacSize()];
|
this.K = new byte[hMac.getMacSize()];
|
||||||
this.counter = Integer.toUnsignedLong(counter);
|
this.counter = (counter == null ? null : Integer.toUnsignedLong(counter));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDeterministic()
|
public boolean isDeterministic()
|
||||||
|
@ -74,8 +74,12 @@ public class HMacDSANonceKCalculator implements DSAKCalculator {
|
||||||
|
|
||||||
System.arraycopy(mVal, 0, m, m.length - mVal.length, mVal.length);
|
System.arraycopy(mVal, 0, m, m.length - mVal.length, mVal.length);
|
||||||
|
|
||||||
|
byte[] c = null;
|
||||||
|
if(counter != null) {
|
||||||
BigInteger additional = BigInteger.valueOf(counter);
|
BigInteger additional = BigInteger.valueOf(counter);
|
||||||
byte[] aData = Utils.bigIntegerToBytes(additional, size);
|
c = Utils.bigIntegerToBytes(additional, size);
|
||||||
|
Utils.reverse(c);
|
||||||
|
}
|
||||||
|
|
||||||
hMac.init(new KeyParameter(K));
|
hMac.init(new KeyParameter(K));
|
||||||
|
|
||||||
|
@ -83,7 +87,9 @@ public class HMacDSANonceKCalculator implements DSAKCalculator {
|
||||||
hMac.update((byte)0x00);
|
hMac.update((byte)0x00);
|
||||||
hMac.update(x, 0, x.length);
|
hMac.update(x, 0, x.length);
|
||||||
hMac.update(m, 0, m.length);
|
hMac.update(m, 0, m.length);
|
||||||
hMac.update(aData, 0, aData.length);
|
if(c != null) {
|
||||||
|
hMac.update(c, 0, c.length);
|
||||||
|
}
|
||||||
|
|
||||||
hMac.doFinal(K, 0);
|
hMac.doFinal(K, 0);
|
||||||
|
|
||||||
|
@ -97,6 +103,9 @@ public class HMacDSANonceKCalculator implements DSAKCalculator {
|
||||||
hMac.update((byte)0x01);
|
hMac.update((byte)0x01);
|
||||||
hMac.update(x, 0, x.length);
|
hMac.update(x, 0, x.length);
|
||||||
hMac.update(m, 0, m.length);
|
hMac.update(m, 0, m.length);
|
||||||
|
if(counter != null) {
|
||||||
|
hMac.update(c, 0, c.length);
|
||||||
|
}
|
||||||
|
|
||||||
hMac.doFinal(K, 0);
|
hMac.doFinal(K, 0);
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class PSBTEntry {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
bb.get(buf);
|
bb.get(buf);
|
||||||
reverse(buf);
|
Utils.reverse(buf);
|
||||||
ByteBuffer pbuf = ByteBuffer.wrap(buf);
|
ByteBuffer pbuf = ByteBuffer.wrap(buf);
|
||||||
path.add(new ChildNumber(pbuf.getInt()));
|
path.add(new ChildNumber(pbuf.getInt()));
|
||||||
} while(bb.hasRemaining());
|
} while(bb.hasRemaining());
|
||||||
|
@ -202,14 +202,6 @@ public class PSBTEntry {
|
||||||
return bb.array();
|
return bb.array();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void reverse(byte[] array) {
|
|
||||||
for (int i = 0; i < array.length / 2; i++) {
|
|
||||||
byte temp = array[i];
|
|
||||||
array[i] = array[array.length - i - 1];
|
|
||||||
array[array.length - i - 1] = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void checkOneByteKey() throws PSBTParseException {
|
public void checkOneByteKey() throws PSBTParseException {
|
||||||
if(this.getKey().length != 1) {
|
if(this.getKey().length != 1) {
|
||||||
throw new PSBTParseException("PSBT key type must be one byte");
|
throw new PSBTParseException("PSBT key type must be one byte");
|
||||||
|
|
Loading…
Reference in a new issue