use of com.sparrowwallet.drongo.crypto.ECKey in project drongo by sparrowwallet.
the class Wallet method getSignedKeystores.
/**
* Determines which keystores have signed a PSBT
*
* @param psbt The partially signed or finalized PSBT
* @return A map keyed with the PSBTInput mapped to a map of the signatures and associated keystores that signed it
*/
public Map<PSBTInput, Map<TransactionSignature, Keystore>> getSignedKeystores(PSBT psbt) {
Map<PSBTInput, WalletNode> signingNodes = getSigningNodes(psbt);
Map<PSBTInput, Map<TransactionSignature, Keystore>> signedKeystores = new LinkedHashMap<>();
for (PSBTInput psbtInput : signingNodes.keySet()) {
WalletNode walletNode = signingNodes.get(psbtInput);
Wallet signingWallet = walletNode.getWallet();
Map<ECKey, Keystore> keystoreKeysForNode = signingWallet.getKeystores().stream().collect(Collectors.toMap(keystore -> signingWallet.getScriptType().getOutputKey(keystore.getPubKey(walletNode)), Function.identity(), (u, v) -> {
throw new IllegalStateException("Duplicate keys from different keystores for node " + walletNode);
}, LinkedHashMap::new));
Map<ECKey, TransactionSignature> keySignatureMap;
if (psbt.isFinalized() || psbtInput.isTaproot()) {
keySignatureMap = psbtInput.getSigningKeys(keystoreKeysForNode.keySet());
} else {
keySignatureMap = psbtInput.getPartialSignatures();
}
keystoreKeysForNode.keySet().retainAll(keySignatureMap.keySet());
Map<TransactionSignature, Keystore> inputSignatureKeystores = new LinkedHashMap<>();
for (ECKey signingKey : keystoreKeysForNode.keySet()) {
inputSignatureKeystores.put(keySignatureMap.get(signingKey), keystoreKeysForNode.get(signingKey));
}
signedKeystores.put(psbtInput, inputSignatureKeystores);
}
return signedKeystores;
}
use of com.sparrowwallet.drongo.crypto.ECKey in project drongo by sparrowwallet.
the class Wallet method getSignedKeystores.
/**
* Determines which keystores have signed a transaction
*
* @param transaction The signed transaction
* @return A map keyed with the transactionInput mapped to a map of the signatures and associated keystores that signed it
*/
public Map<TransactionInput, Map<TransactionSignature, Keystore>> getSignedKeystores(Transaction transaction) {
Map<TransactionInput, WalletNode> signingNodes = getSigningNodes(transaction);
Map<TransactionInput, Map<TransactionSignature, Keystore>> signedKeystores = new LinkedHashMap<>();
for (TransactionInput txInput : signingNodes.keySet()) {
WalletNode walletNode = signingNodes.get(txInput);
Wallet signingWallet = walletNode.getWallet();
Map<ECKey, Keystore> keystoreKeysForNode = signingWallet.getKeystores().stream().collect(Collectors.toMap(keystore -> signingWallet.getScriptType().getOutputKey(keystore.getPubKey(walletNode)), Function.identity(), (u, v) -> {
throw new IllegalStateException("Duplicate keys from different keystores for node " + walletNode);
}, LinkedHashMap::new));
Map<ECKey, TransactionSignature> keySignatureMap = new LinkedHashMap<>();
BlockTransaction blockTransaction = signingWallet.transactions.get(txInput.getOutpoint().getHash());
if (blockTransaction != null && blockTransaction.getTransaction().getOutputs().size() > txInput.getOutpoint().getIndex()) {
TransactionOutput spentTxo = blockTransaction.getTransaction().getOutputs().get((int) txInput.getOutpoint().getIndex());
Script signingScript = getSigningScript(txInput, spentTxo);
Sha256Hash hash;
if (signingWallet.getScriptType() == P2TR) {
List<TransactionOutput> spentOutputs = transaction.getInputs().stream().map(input -> signingWallet.transactions.get(input.getOutpoint().getHash()).getTransaction().getOutputs().get((int) input.getOutpoint().getIndex())).collect(Collectors.toList());
hash = transaction.hashForTaprootSignature(spentOutputs, txInput.getIndex(), !P2TR.isScriptType(signingScript), signingScript, SigHash.ALL_TAPROOT, null);
} else if (txInput.hasWitness()) {
hash = transaction.hashForWitnessSignature(txInput.getIndex(), signingScript, spentTxo.getValue(), SigHash.ALL);
} else {
hash = transaction.hashForLegacySignature(txInput.getIndex(), signingScript, SigHash.ALL);
}
for (ECKey sigPublicKey : keystoreKeysForNode.keySet()) {
for (TransactionSignature signature : txInput.hasWitness() ? txInput.getWitness().getSignatures() : txInput.getScriptSig().getSignatures()) {
if (sigPublicKey.verify(hash, signature)) {
keySignatureMap.put(sigPublicKey, signature);
}
}
}
keystoreKeysForNode.keySet().retainAll(keySignatureMap.keySet());
Map<TransactionSignature, Keystore> inputSignatureKeystores = new LinkedHashMap<>();
for (ECKey signingKey : keystoreKeysForNode.keySet()) {
inputSignatureKeystores.put(keySignatureMap.get(signingKey), keystoreKeysForNode.get(signingKey));
}
signedKeystores.put(txInput, inputSignatureKeystores);
}
}
return signedKeystores;
}
use of com.sparrowwallet.drongo.crypto.ECKey in project drongo by sparrowwallet.
the class Script method getToAddresses.
/**
* Gets the destination address from this script, if it's in the required form.
*/
public Address[] getToAddresses() throws NonStandardScriptException {
for (ScriptType scriptType : SINGLE_HASH_TYPES) {
if (scriptType.isScriptType(this)) {
return new Address[] { scriptType.getAddress(scriptType.getHashFromScript(this)) };
}
}
// Special handling for taproot tweaked keys - we don't want to tweak them again
if (P2TR.isScriptType(this)) {
return new Address[] { new P2TRAddress(P2TR.getPublicKeyFromScript(this).getPubKeyXCoord()) };
}
for (ScriptType scriptType : SINGLE_KEY_TYPES) {
if (scriptType.isScriptType(this)) {
return new Address[] { scriptType.getAddress(scriptType.getPublicKeyFromScript(this)) };
}
}
if (MULTISIG.isScriptType(this)) {
List<Address> addresses = new ArrayList<>();
ECKey[] pubKeys = MULTISIG.getPublicKeysFromScript(this);
for (ECKey pubKey : pubKeys) {
addresses.add(new P2PKAddress(pubKey.getPubKey()));
}
return addresses.toArray(new Address[addresses.size()]);
}
throw new NonStandardScriptException("Cannot find addresses in non standard script: " + toString());
}
use of com.sparrowwallet.drongo.crypto.ECKey in project drongo by sparrowwallet.
the class OutputDescriptor method sortExtendedPubKeys.
private List<ExtendedKey> sortExtendedPubKeys(Collection<ExtendedKey> keys) {
List<ExtendedKey> sortedKeys = new ArrayList<>(keys);
if (mapChildrenDerivations == null || mapChildrenDerivations.isEmpty() || mapChildrenDerivations.containsKey(null)) {
return sortedKeys;
}
Utils.LexicographicByteArrayComparator lexicographicByteArrayComparator = new Utils.LexicographicByteArrayComparator();
sortedKeys.sort((o1, o2) -> {
ECKey key1 = getChildKeyForExtendedPubKey(o1);
ECKey key2 = getChildKeyForExtendedPubKey(o2);
return lexicographicByteArrayComparator.compare(key1.getPubKey(), key2.getPubKey());
});
return sortedKeys;
}
use of com.sparrowwallet.drongo.crypto.ECKey in project drongo by sparrowwallet.
the class PaymentCode method getPaymentCode.
public static PaymentCode getPaymentCode(Transaction transaction, Keystore keystore) throws InvalidPaymentCodeException {
try {
TransactionInput txInput = getDesignatedInput(transaction);
ECKey pubKey = getDesignatedPubKey(txInput);
List<ChildNumber> derivation = keystore.getKeyDerivation().getDerivation();
ChildNumber derivationStart = derivation.isEmpty() ? ChildNumber.ZERO_HARDENED : derivation.get(derivation.size() - 1);
ECKey notificationPrivKey = keystore.getBip47ExtendedPrivateKey().getKey(List.of(derivationStart, new ChildNumber(0)));
SecretPoint secretPoint = new SecretPoint(notificationPrivKey.getPrivKeyBytes(), pubKey.getPubKey());
byte[] blindingMask = getMask(secretPoint.ECDHSecretAsBytes(), txInput.getOutpoint().bitcoinSerialize());
byte[] blindedPaymentCode = getOpReturnData(transaction);
return new PaymentCode(PaymentCode.blind(blindedPaymentCode, blindingMask));
} catch (Exception e) {
throw new InvalidPaymentCodeException("Could not determine payment code from transaction", e);
}
}
Aggregations