mirror of
https://github.com/sparrowwallet/drongo.git
synced 2024-12-26 01:56:44 +00:00
sign psbt inputs
This commit is contained in:
parent
9e6cdf74f4
commit
af562dad10
5 changed files with 49 additions and 18 deletions
|
@ -73,11 +73,12 @@ public class ExtendedKey {
|
|||
return buffer.array();
|
||||
}
|
||||
|
||||
public static ExtendedKey fromDescriptor(String extPubKey) {
|
||||
byte[] serializedKey = Base58.decodeChecked(extPubKey);
|
||||
public static ExtendedKey fromDescriptor(String descriptor) {
|
||||
byte[] serializedKey = Base58.decodeChecked(descriptor);
|
||||
ByteBuffer buffer = ByteBuffer.wrap(serializedKey);
|
||||
int header = buffer.getInt();
|
||||
if(!Header.isValidHeader(header)) {
|
||||
int headerInt = buffer.getInt();
|
||||
Header header = Header.getHeader(headerInt);
|
||||
if(header == null) {
|
||||
throw new IllegalArgumentException("Unknown header bytes: " + DeterministicKey.toBase58(serializedKey).substring(0, 4));
|
||||
}
|
||||
|
||||
|
@ -106,8 +107,13 @@ public class ExtendedKey {
|
|||
throw new IllegalArgumentException("Found unexpected data in key");
|
||||
}
|
||||
|
||||
DeterministicKey pubKey = new DeterministicKey(path, chainCode, new LazyECPoint(ECKey.CURVE.getCurve(), data), depth, parentFingerprint);
|
||||
return new ExtendedKey(pubKey, parentFingerprint, childNumber);
|
||||
if(header.isPrivate()) {
|
||||
DeterministicKey prvKey = HDKeyDerivation.createMasterPrivKeyFromBytes(Arrays.copyOfRange(data, 1, 33), chainCode, path);
|
||||
return new ExtendedKey(prvKey, parentFingerprint, childNumber);
|
||||
} else {
|
||||
DeterministicKey pubKey = new DeterministicKey(path, chainCode, new LazyECPoint(ECKey.CURVE.getCurve(), data), depth, parentFingerprint);
|
||||
return new ExtendedKey(pubKey, parentFingerprint, childNumber);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isValid(String extPubKey) {
|
||||
|
@ -206,14 +212,14 @@ public class ExtendedKey {
|
|||
return name.endsWith("prv");
|
||||
}
|
||||
|
||||
public static boolean isValidHeader(int header) {
|
||||
public static Header getHeader(int header) {
|
||||
for(Header extendedKeyHeader : Header.values()) {
|
||||
if(header == extendedKeyHeader.header) {
|
||||
return true;
|
||||
return extendedKeyHeader;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -84,7 +84,7 @@ public class PSBT {
|
|||
Map<ECKey, KeyDerivation> derivedPublicKeys = new LinkedHashMap<>();
|
||||
for(Keystore keystore : wallet.getKeystores()) {
|
||||
WalletNode walletNode = utxoEntry.getValue();
|
||||
derivedPublicKeys.put(keystore.getKey(walletNode.getKeyPurpose(), walletNode.getIndex()), keystore.getKeyDerivation());
|
||||
derivedPublicKeys.put(keystore.getPubKey(walletNode), keystore.getKeyDerivation());
|
||||
}
|
||||
|
||||
PSBTInput psbtInput = new PSBTInput(wallet.getScriptType(), transaction, inputIndex, utxo, utxoIndex, redeemScript, witnessScript, derivedPublicKeys, Collections.emptyMap());
|
||||
|
@ -119,7 +119,7 @@ public class PSBT {
|
|||
|
||||
Map<ECKey, KeyDerivation> derivedPublicKeys = new LinkedHashMap<>();
|
||||
for(Keystore keystore : wallet.getKeystores()) {
|
||||
derivedPublicKeys.put(keystore.getKey(outputNode.getKeyPurpose(), outputNode.getIndex()), keystore.getKeyDerivation());
|
||||
derivedPublicKeys.put(keystore.getPubKey(outputNode), keystore.getKeyDerivation());
|
||||
}
|
||||
|
||||
PSBTOutput walletOutput = new PSBTOutput(redeemScript, witnessScript, derivedPublicKeys, Collections.emptyMap());
|
||||
|
|
|
@ -280,7 +280,7 @@ public class PSBTInput {
|
|||
}
|
||||
}
|
||||
|
||||
boolean sign(ECKey privKey) {
|
||||
public boolean sign(ECKey privKey) {
|
||||
SigHash localSigHash = getSigHash();
|
||||
if(localSigHash == null) {
|
||||
//Assume SigHash.ALL
|
||||
|
|
|
@ -101,14 +101,26 @@ public class Keystore {
|
|||
public ExtendedKey getExtendedPrivateKey() throws MnemonicException {
|
||||
List<ChildNumber> derivation = getKeyDerivation().getDerivation();
|
||||
DeterministicKey derivedKey = getExtendedMasterPrivateKey().getKey(derivation);
|
||||
return new ExtendedKey(derivedKey, derivedKey.getParentFingerprint(), derivation.get(derivation.size() - 1));
|
||||
ExtendedKey xprv = new ExtendedKey(derivedKey, derivedKey.getParentFingerprint(), derivation.get(derivation.size() - 1));
|
||||
//Recreate from xprv string to reset path to single ChildNumber at the derived depth
|
||||
return ExtendedKey.fromDescriptor(xprv.toString());
|
||||
}
|
||||
|
||||
public DeterministicKey getKey(WalletNode walletNode) {
|
||||
public DeterministicKey getKey(WalletNode walletNode) throws MnemonicException {
|
||||
return getKey(walletNode.getKeyPurpose(), walletNode.getIndex());
|
||||
}
|
||||
|
||||
public DeterministicKey getKey(KeyPurpose keyPurpose, int keyIndex) {
|
||||
public DeterministicKey getKey(KeyPurpose keyPurpose, int keyIndex) throws MnemonicException {
|
||||
ExtendedKey extendedPrivateKey = getExtendedPrivateKey();
|
||||
List<ChildNumber> derivation = List.of(extendedPrivateKey.getKeyChildNumber(), keyPurpose.getPathIndex(), new ChildNumber(keyIndex));
|
||||
return extendedPrivateKey.getKey(derivation);
|
||||
}
|
||||
|
||||
public DeterministicKey getPubKey(WalletNode walletNode) {
|
||||
return getPubKey(walletNode.getKeyPurpose(), walletNode.getIndex());
|
||||
}
|
||||
|
||||
public DeterministicKey getPubKey(KeyPurpose keyPurpose, int keyIndex) {
|
||||
List<ChildNumber> derivation = List.of(extendedPublicKey.getKeyChildNumber(), keyPurpose.getPathIndex(), new ChildNumber(keyIndex));
|
||||
return extendedPublicKey.getKey(derivation);
|
||||
}
|
||||
|
|
|
@ -169,7 +169,7 @@ public class Wallet {
|
|||
}
|
||||
|
||||
Keystore keystore = getKeystores().get(0);
|
||||
return keystore.getKey(keyPurpose, index);
|
||||
return keystore.getPubKey(keyPurpose, index);
|
||||
}
|
||||
|
||||
public List<ECKey> getPubKeys(WalletNode node) {
|
||||
|
@ -183,7 +183,7 @@ public class Wallet {
|
|||
throw new UnsupportedOperationException("Cannot determine public keys for a custom policy");
|
||||
}
|
||||
|
||||
return getKeystores().stream().map(keystore -> keystore.getKey(keyPurpose, index)).collect(Collectors.toList());
|
||||
return getKeystores().stream().map(keystore -> keystore.getPubKey(keyPurpose, index)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Address getAddress(WalletNode node) {
|
||||
|
@ -615,7 +615,7 @@ public class Wallet {
|
|||
|
||||
for(PSBTInput psbtInput : signingNodes.keySet()) {
|
||||
WalletNode walletNode = signingNodes.get(psbtInput);
|
||||
Map<ECKey, Keystore> keystoreKeysForNode = getKeystores().stream().collect(Collectors.toMap(keystore -> keystore.getKey(walletNode), Function.identity(),
|
||||
Map<ECKey, Keystore> keystoreKeysForNode = getKeystores().stream().collect(Collectors.toMap(keystore -> keystore.getPubKey(walletNode), Function.identity(),
|
||||
(u, v) -> { throw new IllegalStateException("Duplicate keys from different keystores for node " + walletNode.getDerivationPath()); },
|
||||
LinkedHashMap::new));
|
||||
|
||||
|
@ -628,6 +628,19 @@ public class Wallet {
|
|||
return signedKeystores;
|
||||
}
|
||||
|
||||
public void sign(PSBT psbt) throws MnemonicException {
|
||||
Map<PSBTInput, WalletNode> signingNodes = getSigningNodes(psbt);
|
||||
for(Keystore keystore : getKeystores()) {
|
||||
if(keystore.hasSeed()) {
|
||||
for(Map.Entry<PSBTInput, WalletNode> signingEntry : signingNodes.entrySet()) {
|
||||
ECKey privKey = keystore.getKey(signingEntry.getValue());
|
||||
PSBTInput psbtInput = signingEntry.getKey();
|
||||
psbtInput.sign(privKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BitcoinUnit getAutoUnit() {
|
||||
for(KeyPurpose keyPurpose : KeyPurpose.values()) {
|
||||
for(WalletNode addressNode : getNode(keyPurpose).getChildren()) {
|
||||
|
|
Loading…
Reference in a new issue