BitcoinUtil { public static byte[] getTransactionHashSegwit(BitcoinTransaction transaction) throws IOException{ ByteArrayOutputStream transactionBAOS = new ByteArrayOutputStream(); byte[] version = reverseByteArray(convertIntToByteArray(transaction.getVersion())); transactionBAOS.write(version); boolean segwit=false; if ((transaction.getMarker()==0) && (transaction.getFlag()!=0)) { segwit=true; boolean emptyWitness=true; for (int k=0;k<transaction.getBitcoinScriptWitness().size();k++) { BitcoinScriptWitnessItem currentItem = transaction.getBitcoinScriptWitness().get(k); if (currentItem.getStackItemCounter().length>1) { emptyWitness=false; break; } else if ((currentItem.getStackItemCounter().length==1) && (currentItem.getStackItemCounter()[0]!=0x00)) { emptyWitness=false; break; } } if (emptyWitness==true) { return BitcoinUtil.getTransactionHashSegwit(transaction); } transactionBAOS.write(transaction.getMarker()); transactionBAOS.write(transaction.getFlag()); } byte[] inCounter = transaction.getInCounter(); transactionBAOS.write(inCounter); for (int i=0;i<transaction.getListOfInputs().size();i++) { transactionBAOS.write(transaction.getListOfInputs().get(i).getPrevTransactionHash()); transactionBAOS.write(reverseByteArray(convertIntToByteArray((int)(transaction.getListOfInputs().get(i).getPreviousTxOutIndex())))); transactionBAOS.write(transaction.getListOfInputs().get(i).getTxInScriptLength()); transactionBAOS.write(transaction.getListOfInputs().get(i).getTxInScript()); transactionBAOS.write(reverseByteArray(convertIntToByteArray((int)(transaction.getListOfInputs().get(i).getSeqNo())))); } byte[] outCounter = transaction.getOutCounter(); transactionBAOS.write(outCounter); for (int j=0;j<transaction.getListOfOutputs().size();j++) { transactionBAOS.write(convertBigIntegerToByteArray(transaction.getListOfOutputs().get(j).getValue(),8)); transactionBAOS.write(transaction.getListOfOutputs().get(j).getTxOutScriptLength()); transactionBAOS.write(transaction.getListOfOutputs().get(j).getTxOutScript()); } if (segwit) { for (int k=0;k<transaction.getBitcoinScriptWitness().size();k++) { BitcoinScriptWitnessItem currentItem = transaction.getBitcoinScriptWitness().get(k); transactionBAOS.write(currentItem.getStackItemCounter()); for (int l=0;l<currentItem.getScriptWitnessList().size();l++) { transactionBAOS.write(currentItem.getScriptWitnessList().get(l).getWitnessScriptLength()); transactionBAOS.write(currentItem.getScriptWitnessList().get(l).getWitnessScript()); } } } byte[] lockTime=reverseByteArray(convertIntToByteArray(transaction.getLockTime())); transactionBAOS.write(lockTime); byte[] transactionByteArray= transactionBAOS.toByteArray(); byte[] firstRoundHash; byte[] secondRoundHash; try { MessageDigest digest = MessageDigest.getInstance("SHA-256"); firstRoundHash = digest.digest(transactionByteArray); secondRoundHash = digest.digest(firstRoundHash); } catch (NoSuchAlgorithmException nsae) { LOG.error(nsae); return new byte[0]; } return secondRoundHash; } private  BitcoinUtil(); static long convertSignedIntToUnsigned(int signedInt); static byte[] convertIntToByteArray(int intToConvert); static byte[] convertLongToByteArray(long longToConvert); static byte[] convertBigIntegerToByteArray(BigInteger bigIntegerToConvert,int exactArraySize); static byte[] convertVarIntByteBufferToByteArray(ByteBuffer byteBuffer); static long convertVarIntByteBufferToLong(ByteBuffer byteBuffer); static BigInteger getVarIntBI(byte[] varInt); static long getVarInt(byte[] varInt); static byte getVarIntSize(byte firstByteVarInt); static long getSize(byte[] byteSize); static byte[] reverseByteArray(byte[] inputByteArray); static byte[] convertHexStringToByteArray(String hexString); static String convertByteArrayToHexString(byte[] byteArray); static Date convertIntToDate(int dateInt); static boolean compareMagics(byte[] magic1,byte[] magic2); static byte[] getTransactionHash(BitcoinTransaction transaction); static byte[] getTransactionHashSegwit(BitcoinTransaction transaction);  }
@Test public void getTransactionHashSegWit() throws NoSuchAlgorithmException, IOException { int version=2; byte marker=0x00; byte flag=0x01; byte[] inCounter = new byte[]{0x01}; byte[] previousTransactionHash = new byte[]{(byte)0x07,(byte)0x21,(byte)0x35,(byte)0x23,(byte)0x6D,(byte)0x2E,(byte)0xBC,(byte)0x78,(byte)0xB6,(byte)0xAC,(byte)0xE1,(byte)0x88,(byte)0x97,(byte)0x03,(byte)0xB1,(byte)0x84,(byte)0x85,(byte)0x52,(byte)0x87,(byte)0x12,(byte)0xBD,(byte)0x70,(byte)0xE0,(byte)0x7F,(byte)0x4A,(byte)0x90,(byte)0x11,(byte)0x40,(byte)0xDE,(byte)0x38,(byte)0xA2,(byte)0xE8}; long previousTxOutIndex = 1L; byte[] txInScriptLength = new byte[]{(byte)0x17}; byte[] txInScript= new byte[]{(byte)0x16,(byte)0x00,(byte)0x14,(byte)0x4D,(byte)0x4D,(byte)0x83,(byte)0xED,(byte)0x5F,(byte)0x10,(byte)0x7B,(byte)0x8D,(byte)0x45,(byte)0x1E,(byte)0x59,(byte)0xA0,(byte)0x43,(byte)0x1A,(byte)0x13,(byte)0x92,(byte)0x79,(byte)0x6B,(byte)0x26,(byte)0x04}; long seqNo=4294967295L; byte[] outCounter = new byte[]{0x02}; long value_1=1009051983L; byte[] txOutScriptLength_1=new byte[]{(byte)0x17}; byte[] txOutScript_1=new byte[]{(byte)0xA9,(byte)0x14,(byte)0xF0,(byte)0x50,(byte)0xC5,(byte)0x91,(byte)0xEA,(byte)0x98,(byte)0x26,(byte)0x73,(byte)0xCC,(byte)0xED,(byte)0xF5,(byte)0x21,(byte)0x13,(byte)0x65,(byte)0x7B,(byte)0x67,(byte)0x83,(byte)0x03,(byte)0xE6,(byte)0xA1,(byte)0x87}; long value_2=59801109L; byte[] txOutScriptLength_2=new byte[]{(byte)0x19}; byte[] txOutScript_2=new byte[]{(byte)0x76,(byte)0xA9,(byte)0x14,(byte)0xFB,(byte)0x2E,(byte)0x13,(byte)0x83,(byte)0x5E,(byte)0x39,(byte)0x88,(byte)0xC7,(byte)0x8F,(byte)0x76,(byte)0x0D,(byte)0x4A,(byte)0xC8,(byte)0x1E,(byte)0x04,(byte)0xEA,(byte)0xF1,(byte)0x94,(byte)0xEA,(byte)0x92,(byte)0x88,(byte)0xAC}; byte[] noOfStackItems = new byte[]{0x02}; byte[] segwitnessLength_1=new byte[]{(byte)0x48}; byte[] segwitnessScript_1 = new byte[]{(byte)0x30,(byte)0x45,(byte)0x02,(byte)0x21,(byte)0x00,(byte)0xBB,(byte)0x5F,(byte)0x78,(byte)0xE8,(byte)0xA1,(byte)0xBA,(byte)0x5E,(byte)0x14,(byte)0x26,(byte)0x1B,(byte)0x0A,(byte)0xD3,(byte)0x95,(byte)0x56,(byte)0xAF,(byte)0x9B,(byte)0x21,(byte)0xD9,(byte)0x1F,(byte)0x67,(byte)0x5D,(byte)0x38,(byte)0xC8,(byte)0xCD,(byte)0xAD,(byte)0x7E,(byte)0x7F,(byte)0x5D,(byte)0x21,(byte)0x00,(byte)0x4A,(byte)0xBD,(byte)0x02,(byte)0x20,(byte)0x4C,(byte)0x1E,(byte)0xAC,(byte)0xF1,(byte)0xF9,(byte)0xAC,(byte)0x1D,(byte)0xCC,(byte)0x61,(byte)0x63,(byte)0xF2,(byte)0x07,(byte)0xFC,(byte)0xBC,(byte)0x49,(byte)0x8B,(byte)0x32,(byte)0x4C,(byte)0xBE,(byte)0xF5,(byte)0x7F,(byte)0x83,(byte)0x9F,(byte)0xA2,(byte)0xC2,(byte)0x55,(byte)0x57,(byte)0x4B,(byte)0x2F,(byte)0x37,(byte)0x19,(byte)0xBC,(byte)0x01}; byte[] segwitnessLength_2=new byte[]{(byte)0x21}; byte[] segwitnessScript_2 = new byte[]{(byte)0x03,(byte)0xC5,(byte)0x3F,(byte)0xEA,(byte)0x9A,(byte)0xE5,(byte)0x61,(byte)0xB6,(byte)0x05,(byte)0x74,(byte)0xB2,(byte)0xD5,(byte)0x10,(byte)0x27,(byte)0x3F,(byte)0x7C,(byte)0x51,(byte)0x60,(byte)0x69,(byte)0x7E,(byte)0xB4,(byte)0x7B,(byte)0x48,(byte)0x8E,(byte)0x95,(byte)0xAD,(byte)0x62,(byte)0x91,(byte)0xBB,(byte)0xCB,(byte)0x5E,(byte)0x43,(byte)0xA2}; int lockTime = 0; List<BitcoinTransactionInput> randomScriptWitnessInput = new ArrayList<BitcoinTransactionInput>(1); randomScriptWitnessInput.add(new BitcoinTransactionInput(previousTransactionHash,previousTxOutIndex,txInScriptLength,txInScript,seqNo)); List<BitcoinTransactionOutput> randomScriptWitnessOutput = new ArrayList<BitcoinTransactionOutput>(2); randomScriptWitnessOutput.add(new BitcoinTransactionOutput(BigInteger.valueOf(value_1),txOutScriptLength_1,txOutScript_1)); randomScriptWitnessOutput.add(new BitcoinTransactionOutput(BigInteger.valueOf(value_2),txOutScriptLength_2,txOutScript_2)); List<BitcoinScriptWitnessItem> randomScriptWitnessSWI = new ArrayList<BitcoinScriptWitnessItem>(1); List<BitcoinScriptWitness> randomScriptWitnessSW = new ArrayList<BitcoinScriptWitness>(2); randomScriptWitnessSW.add(new BitcoinScriptWitness(segwitnessLength_1,segwitnessScript_1)); randomScriptWitnessSW.add(new BitcoinScriptWitness(segwitnessLength_2,segwitnessScript_2)); randomScriptWitnessSWI.add(new BitcoinScriptWitnessItem(noOfStackItems,randomScriptWitnessSW)); BitcoinTransaction randomScriptWitnessTransaction = new BitcoinTransaction(marker,flag,version,inCounter,randomScriptWitnessInput,outCounter,randomScriptWitnessOutput,randomScriptWitnessSWI,lockTime); byte[] randomScriptWitnessTransactionHash=BitcoinUtil.getTransactionHash(randomScriptWitnessTransaction); byte[] expectedHash = BitcoinUtil.reverseByteArray(new byte[]{(byte)0x47,(byte)0x52,(byte)0x1C,(byte)0x2A,(byte)0x13,(byte)0x45,(byte)0x5E,(byte)0x92,(byte)0xD3,(byte)0xBD,(byte)0x56,(byte)0x3F,(byte)0xAD,(byte)0xA5,(byte)0x78,(byte)0x6E,(byte)0x85,(byte)0xB4,(byte)0x5E,(byte)0x96,(byte)0x85,(byte)0xA8,(byte)0xC9,(byte)0xA3,(byte)0xFE,(byte)0xB8,(byte)0x9A,(byte)0x4F,(byte)0xB5,(byte)0x0D,(byte)0xAF,(byte)0xF5}); assertArrayEquals( expectedHash, randomScriptWitnessTransactionHash,"Hash for Random ScriptWitness Transaction correctly calculated (txId)"); byte[] randomScriptWitnessTransactionHashSegWit=BitcoinUtil.getTransactionHashSegwit(randomScriptWitnessTransaction); byte[] expectedHashSegwit = BitcoinUtil.reverseByteArray(new byte[]{(byte)0x74,(byte)0x70,(byte)0x0E,(byte)0x2C,(byte)0xE0,(byte)0x30,(byte)0x01,(byte)0x3E,(byte)0x2E,(byte)0x10,(byte)0xFC,(byte)0xFD,(byte)0x06,(byte)0xDF,(byte)0x99,(byte)0xC7,(byte)0x82,(byte)0x6E,(byte)0x41,(byte)0xC7,(byte)0x25,(byte)0xCA,(byte)0x5C,(byte)0x46,(byte)0x76,(byte)0x60,(byte)0xBF,(byte)0xA4,(byte)0x87,(byte)0x4F,(byte)0x65,(byte)0xBF}); assertArrayEquals( expectedHashSegwit, randomScriptWitnessTransactionHashSegWit,"Hash for Random ScriptWitness Transaction correctly calculated (wtxId)"); }