mirror of
https://github.com/sparrowwallet/drongo.git
synced 2024-12-27 10:36:45 +00:00
grind for low r, for psbt ensure if a witness UTXO is provided, no non-witness signature may be created
This commit is contained in:
parent
af562dad10
commit
f2ee57cc4d
3 changed files with 180 additions and 9 deletions
|
@ -461,6 +461,10 @@ public class ECKey implements EncryptableItem {
|
||||||
return bos;
|
return bos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean hasLowR() {
|
||||||
|
return r.toByteArray().length <= 32;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
@ -517,11 +521,18 @@ public class ECKey implements EncryptableItem {
|
||||||
throw new IllegalArgumentException("Private key cannot be null");
|
throw new IllegalArgumentException("Private key cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));
|
ECDSASignature signature;
|
||||||
|
int counter = 0;
|
||||||
|
do {
|
||||||
|
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());
|
||||||
return new ECDSASignature(components[0], components[1]).toCanonicalised();
|
signature = new ECDSASignature(components[0], components[1]).toCanonicalised();
|
||||||
|
counter++;
|
||||||
|
} while(!signature.hasLowR());
|
||||||
|
|
||||||
|
return signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
package com.sparrowwallet.drongo.crypto;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.Utils;
|
||||||
|
import org.bouncycastle.crypto.Digest;
|
||||||
|
import org.bouncycastle.crypto.macs.HMac;
|
||||||
|
import org.bouncycastle.crypto.params.KeyParameter;
|
||||||
|
import org.bouncycastle.crypto.signers.DSAKCalculator;
|
||||||
|
import org.bouncycastle.util.Arrays;
|
||||||
|
import org.bouncycastle.util.BigIntegers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A deterministic K calculator based on the algorithm in section 3.2 of RFC 6979.
|
||||||
|
* This is a copy of org.bouncycastle.crypto.signers.HMacDSAKCalculator, with support for section 3.6 of RFC 6979 (additional data)
|
||||||
|
*/
|
||||||
|
public class HMacDSANonceKCalculator implements DSAKCalculator {
|
||||||
|
private static final BigInteger ZERO = BigInteger.valueOf(0);
|
||||||
|
|
||||||
|
private final HMac hMac;
|
||||||
|
private final byte[] K;
|
||||||
|
private final byte[] V;
|
||||||
|
private final long counter;
|
||||||
|
|
||||||
|
private BigInteger n;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base constructor.
|
||||||
|
*
|
||||||
|
* @param digest digest to build the HMAC on.
|
||||||
|
* @param counter additional data as per RFC 6979 3.6
|
||||||
|
*/
|
||||||
|
public HMacDSANonceKCalculator(Digest digest, int counter) {
|
||||||
|
this.hMac = new HMac(digest);
|
||||||
|
this.V = new byte[hMac.getMacSize()];
|
||||||
|
this.K = new byte[hMac.getMacSize()];
|
||||||
|
this.counter = Integer.toUnsignedLong(counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDeterministic()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(BigInteger n, SecureRandom random)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Operation not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(BigInteger n, BigInteger d, byte[] message)
|
||||||
|
{
|
||||||
|
this.n = n;
|
||||||
|
|
||||||
|
Arrays.fill(V, (byte)0x01);
|
||||||
|
Arrays.fill(K, (byte)0);
|
||||||
|
|
||||||
|
int size = BigIntegers.getUnsignedByteLength(n);
|
||||||
|
byte[] x = new byte[size];
|
||||||
|
byte[] dVal = BigIntegers.asUnsignedByteArray(d);
|
||||||
|
|
||||||
|
System.arraycopy(dVal, 0, x, x.length - dVal.length, dVal.length);
|
||||||
|
|
||||||
|
byte[] m = new byte[size];
|
||||||
|
|
||||||
|
BigInteger mInt = bitsToInt(message);
|
||||||
|
|
||||||
|
if (mInt.compareTo(n) >= 0)
|
||||||
|
{
|
||||||
|
mInt = mInt.subtract(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] mVal = BigIntegers.asUnsignedByteArray(mInt);
|
||||||
|
|
||||||
|
System.arraycopy(mVal, 0, m, m.length - mVal.length, mVal.length);
|
||||||
|
|
||||||
|
BigInteger additional = BigInteger.valueOf(counter);
|
||||||
|
byte[] aData = Utils.bigIntegerToBytes(additional, size);
|
||||||
|
|
||||||
|
hMac.init(new KeyParameter(K));
|
||||||
|
|
||||||
|
hMac.update(V, 0, V.length);
|
||||||
|
hMac.update((byte)0x00);
|
||||||
|
hMac.update(x, 0, x.length);
|
||||||
|
hMac.update(m, 0, m.length);
|
||||||
|
hMac.update(aData, 0, aData.length);
|
||||||
|
|
||||||
|
hMac.doFinal(K, 0);
|
||||||
|
|
||||||
|
hMac.init(new KeyParameter(K));
|
||||||
|
|
||||||
|
hMac.update(V, 0, V.length);
|
||||||
|
|
||||||
|
hMac.doFinal(V, 0);
|
||||||
|
|
||||||
|
hMac.update(V, 0, V.length);
|
||||||
|
hMac.update((byte)0x01);
|
||||||
|
hMac.update(x, 0, x.length);
|
||||||
|
hMac.update(m, 0, m.length);
|
||||||
|
|
||||||
|
hMac.doFinal(K, 0);
|
||||||
|
|
||||||
|
hMac.init(new KeyParameter(K));
|
||||||
|
|
||||||
|
hMac.update(V, 0, V.length);
|
||||||
|
|
||||||
|
hMac.doFinal(V, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger nextK()
|
||||||
|
{
|
||||||
|
byte[] t = new byte[BigIntegers.getUnsignedByteLength(n)];
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int tOff = 0;
|
||||||
|
|
||||||
|
while (tOff < t.length)
|
||||||
|
{
|
||||||
|
hMac.update(V, 0, V.length);
|
||||||
|
|
||||||
|
hMac.doFinal(V, 0);
|
||||||
|
|
||||||
|
int len = Math.min(t.length - tOff, V.length);
|
||||||
|
System.arraycopy(V, 0, t, tOff, len);
|
||||||
|
tOff += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger k = bitsToInt(t);
|
||||||
|
|
||||||
|
if (k.compareTo(ZERO) > 0 && k.compareTo(n) < 0)
|
||||||
|
{
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
hMac.update(V, 0, V.length);
|
||||||
|
hMac.update((byte)0x00);
|
||||||
|
|
||||||
|
hMac.doFinal(K, 0);
|
||||||
|
|
||||||
|
hMac.init(new KeyParameter(K));
|
||||||
|
|
||||||
|
hMac.update(V, 0, V.length);
|
||||||
|
|
||||||
|
hMac.doFinal(V, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigInteger bitsToInt(byte[] t)
|
||||||
|
{
|
||||||
|
BigInteger v = new BigInteger(1, t);
|
||||||
|
|
||||||
|
if (t.length * 8 > n.bitLength())
|
||||||
|
{
|
||||||
|
v = v.shiftRight(t.length * 8 - n.bitLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
|
@ -334,7 +334,7 @@ public class PSBTInput {
|
||||||
|
|
||||||
public Script getSigningScript() {
|
public Script getSigningScript() {
|
||||||
int vout = (int)transaction.getInputs().get(index).getOutpoint().getIndex();
|
int vout = (int)transaction.getInputs().get(index).getOutpoint().getIndex();
|
||||||
Script signingScript = getNonWitnessUtxo() != null ? getNonWitnessUtxo().getOutputs().get(vout).getScript() : getWitnessUtxo().getScript();
|
Script signingScript = getWitnessUtxo() != null ? getWitnessUtxo().getScript() : getNonWitnessUtxo().getOutputs().get(vout).getScript();
|
||||||
|
|
||||||
if(P2SH.isScriptType(signingScript)) {
|
if(P2SH.isScriptType(signingScript)) {
|
||||||
if(getRedeemScript() != null) {
|
if(getRedeemScript() != null) {
|
||||||
|
@ -363,11 +363,11 @@ public class PSBTInput {
|
||||||
|
|
||||||
private Sha256Hash getHashForSignature(Script connectedScript, SigHash localSigHash) {
|
private Sha256Hash getHashForSignature(Script connectedScript, SigHash localSigHash) {
|
||||||
Sha256Hash hash;
|
Sha256Hash hash;
|
||||||
if (getNonWitnessUtxo() != null) {
|
if(getWitnessUtxo() != null) {
|
||||||
hash = transaction.hashForSignature(index, connectedScript, localSigHash);
|
|
||||||
} else {
|
|
||||||
long prevValue = getWitnessUtxo().getValue();
|
long prevValue = getWitnessUtxo().getValue();
|
||||||
hash = transaction.hashForWitnessSignature(index, connectedScript, prevValue, localSigHash);
|
hash = transaction.hashForWitnessSignature(index, connectedScript, prevValue, localSigHash);
|
||||||
|
} else {
|
||||||
|
hash = transaction.hashForSignature(index, connectedScript, localSigHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
|
|
Loading…
Reference in a new issue