/* * Copyright 2014 Christopher Mann * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.uni_bonn.bit; import org.bitcoinj.core.ECKey; import org.bitcoinj.core.Transaction; import org.bitcoinj.core.TransactionInput; import org.bitcoinj.script.Script; import de.uni_bonn.bit.wallet_protocol.*; import java.util.HashMap; import java.util.Map; /** * This class implements the phone's logic for signing a Bitcoin transaction with the two-party ECDSA signature * protocol. This class only contains the Bitcoin-specific logic and uses one or more instances of the class * {@link de.uni_bonn.bit.PhoneSigner} to create ECDSA signatures for the transaction inputs with the help of * the two-party ECDSA signature protocol. This class does not return any result. (The signed transaction is * returned by the {@link de.uni_bonn.bit.DesktopTransactionSigner}). */ public class PhoneTransactionSigner { PaillierKeyPair pkpDesktop; PaillierKeyPair pkpPhone; BCParameters desktopBCParameters; BCParameters phoneBCParameters; ECKey privateKey; ECKey otherPublicKey; TransactionInfo transactionInfo; Map<Integer,PhoneSigner> hashSignerMap = new HashMap<>(); public PhoneTransactionSigner(TransactionInfo transactionInfo, ECKey privateKey, ECKey otherPublicKey, PaillierKeyPair pkpDesktop, PaillierKeyPair pkpPhone, BCParameters desktopBCParameters, BCParameters phoneBCParameters) { this.transactionInfo = transactionInfo; this.privateKey = privateKey; this.otherPublicKey = otherPublicKey; this.pkpDesktop = pkpDesktop; this.pkpPhone = pkpPhone; this.desktopBCParameters = desktopBCParameters; this.phoneBCParameters = phoneBCParameters; } public EphemeralValueShare[] generateEphemeralValueShare(SignatureParts[] signatureParts){ if(signatureParts.length != transactionInfo.getTransaction().getInputs().size()){ throw new ProtocolException("The number of signature parts does not fit the number of transaction inputs."); } EphemeralValueShare[] result = new EphemeralValueShare[signatureParts.length]; for(int i = 0; i < signatureParts.length; i++){ PhoneSigner phoneSigner = new PhoneSigner(privateKey, otherPublicKey, pkpDesktop, pkpPhone, desktopBCParameters, phoneBCParameters); hashSignerMap.put(i, phoneSigner); result[i] = phoneSigner.generateEphemeralValueShare(signatureParts[i]); } return result; } public EncryptedSignatureWithProof[] computeEncryptedSignatures(EphemeralPublicValueWithProof[] ephemeralPublicValuesWithProof){ EncryptedSignatureWithProof[] result = new EncryptedSignatureWithProof[transactionInfo.getTransaction().getInputs().size()]; for(int i = 0; i < ephemeralPublicValuesWithProof.length; i++) { EphemeralPublicValueWithProof valueWithProof = ephemeralPublicValuesWithProof[i]; if (valueWithProof != null) { TransactionInput transactionInput = transactionInfo.getTransaction().getInput(i); long outputIndex = transactionInput.getOutpoint().getIndex(); Script scriptPubKey = transactionInfo.getConnectedTransactionsForInput(i).getOutput((int) outputIndex).getScriptPubKey(); byte[] hashToSign = transactionInfo.getTransaction().hashForSignature(i, scriptPubKey, Transaction.SigHash.ALL, false).getBytes(); result[i] = hashSignerMap.get(i).computeEncryptedSignature(valueWithProof, hashToSign); } } return result; } }