Search in sources :

Example 31 with ECKey

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;
}
Also used : Address(com.sparrowwallet.drongo.address.Address) java.util(java.util) PSBT(com.sparrowwallet.drongo.psbt.PSBT) ChildNumber(com.sparrowwallet.drongo.crypto.ChildNumber) Key(com.sparrowwallet.drongo.crypto.Key) PolicyType(com.sparrowwallet.drongo.policy.PolicyType) Function(java.util.function.Function) Collectors(java.util.stream.Collectors) StandardCharsets(java.nio.charset.StandardCharsets) Policy(com.sparrowwallet.drongo.policy.Policy) PSBTInput(com.sparrowwallet.drongo.psbt.PSBTInput) PSBTOutput(com.sparrowwallet.drongo.psbt.PSBTOutput) com.sparrowwallet.drongo.protocol(com.sparrowwallet.drongo.protocol) ECKey(com.sparrowwallet.drongo.crypto.ECKey) DeterministicKey(com.sparrowwallet.drongo.crypto.DeterministicKey) com.sparrowwallet.drongo(com.sparrowwallet.drongo) ScriptType(com.sparrowwallet.drongo.protocol.ScriptType) PaymentCode(com.sparrowwallet.drongo.bip47.PaymentCode) WITNESS_SCALE_FACTOR(com.sparrowwallet.drongo.protocol.Transaction.WITNESS_SCALE_FACTOR) ECKey(com.sparrowwallet.drongo.crypto.ECKey) PSBTInput(com.sparrowwallet.drongo.psbt.PSBTInput)

Example 32 with ECKey

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;
}
Also used : Address(com.sparrowwallet.drongo.address.Address) java.util(java.util) PSBT(com.sparrowwallet.drongo.psbt.PSBT) ChildNumber(com.sparrowwallet.drongo.crypto.ChildNumber) Key(com.sparrowwallet.drongo.crypto.Key) PolicyType(com.sparrowwallet.drongo.policy.PolicyType) Function(java.util.function.Function) Collectors(java.util.stream.Collectors) StandardCharsets(java.nio.charset.StandardCharsets) Policy(com.sparrowwallet.drongo.policy.Policy) PSBTInput(com.sparrowwallet.drongo.psbt.PSBTInput) PSBTOutput(com.sparrowwallet.drongo.psbt.PSBTOutput) com.sparrowwallet.drongo.protocol(com.sparrowwallet.drongo.protocol) ECKey(com.sparrowwallet.drongo.crypto.ECKey) DeterministicKey(com.sparrowwallet.drongo.crypto.DeterministicKey) com.sparrowwallet.drongo(com.sparrowwallet.drongo) ScriptType(com.sparrowwallet.drongo.protocol.ScriptType) PaymentCode(com.sparrowwallet.drongo.bip47.PaymentCode) WITNESS_SCALE_FACTOR(com.sparrowwallet.drongo.protocol.Transaction.WITNESS_SCALE_FACTOR) ECKey(com.sparrowwallet.drongo.crypto.ECKey)

Example 33 with ECKey

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());
}
Also used : ScriptType(com.sparrowwallet.drongo.protocol.ScriptType) ArrayList(java.util.ArrayList) ECKey(com.sparrowwallet.drongo.crypto.ECKey)

Example 34 with ECKey

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;
}
Also used : ECKey(com.sparrowwallet.drongo.crypto.ECKey)

Example 35 with ECKey

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);
    }
}
Also used : ECKey(com.sparrowwallet.drongo.crypto.ECKey) ChildNumber(com.sparrowwallet.drongo.crypto.ChildNumber) BufferUnderflowException(java.nio.BufferUnderflowException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) InvalidKeyException(java.security.InvalidKeyException)

Aggregations

ECKey (com.sparrowwallet.drongo.crypto.ECKey)45 Test (org.junit.Test)22 ByteArrayOutputStream (java.io.ByteArrayOutputStream)7 Address (com.sparrowwallet.drongo.address.Address)6 ChildNumber (com.sparrowwallet.drongo.crypto.ChildNumber)6 PaymentCode (com.sparrowwallet.drongo.bip47.PaymentCode)5 PSBT (com.sparrowwallet.drongo.psbt.PSBT)5 PSBTInput (com.sparrowwallet.drongo.psbt.PSBTInput)5 InvalidAddressException (com.sparrowwallet.drongo.address.InvalidAddressException)4 ScriptType (com.sparrowwallet.drongo.protocol.ScriptType)4 SecureString (com.sparrowwallet.drongo.SecureString)3 SecretPoint (com.sparrowwallet.drongo.bip47.SecretPoint)3 DeterministicKey (com.sparrowwallet.drongo.crypto.DeterministicKey)3 SchnorrSignature (com.sparrowwallet.drongo.crypto.SchnorrSignature)3 PSBTOutput (com.sparrowwallet.drongo.psbt.PSBTOutput)3 StandardCharsets (java.nio.charset.StandardCharsets)3 java.util (java.util)3 Collectors (java.util.stream.Collectors)3 Subscribe (com.google.common.eventbus.Subscribe)2 Files (com.google.common.io.Files)2