├── settings.gradle ├── .gitignore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src ├── main │ └── java │ │ └── org │ │ └── twostack │ │ └── bitcoin4j │ │ ├── params │ │ ├── AddressType.java │ │ ├── NetworkType.java │ │ ├── NetworkAddressType.java │ │ └── NetworkParameters.java │ │ ├── exception │ │ ├── SigHashException.java │ │ ├── InvalidKeyException.java │ │ ├── TransactionException.java │ │ ├── PubKeyEncodingException.java │ │ ├── SignatureEncodingException.java │ │ ├── ProtocolException.java │ │ ├── SignatureDecodeException.java │ │ ├── MnemonicException.java │ │ ├── VerificationException.java │ │ └── AddressFormatException.java │ │ ├── transaction │ │ ├── P2SHUnlockBuilder.java │ │ ├── DefaultLockBuilder.java │ │ ├── LockingScriptBuilder.java │ │ ├── P2SHLockBuilder.java │ │ ├── DefaultUnlockBuilder.java │ │ ├── TransactionOption.java │ │ ├── UnlockingScriptBuilder.java │ │ ├── SigHashType.java │ │ ├── P2PKLockBuilder.java │ │ ├── P2MSUnlockBuilder.java │ │ ├── P2PKUnlockBuilder.java │ │ ├── UnspendableDataLockBuilder.java │ │ ├── TransactionOutpoint.java │ │ ├── P2PKHUnlockBuilder.java │ │ ├── P2PKHLockBuilder.java │ │ ├── P2MSLockBuilder.java │ │ ├── TransactionOutput.java │ │ ├── WriteUtils.java │ │ ├── ReadUtils.java │ │ └── P2PKHDataLockBuilder.java │ │ ├── crypto │ │ ├── HDDerivationException.java │ │ ├── EncryptedData.java │ │ ├── DRMWorkaround.java │ │ ├── HDUtils.java │ │ ├── LinuxSecureRandom.java │ │ ├── ChildNumber.java │ │ ├── PBKDF2SHA512.java │ │ └── DumpedPrivateKey.java │ │ ├── utils │ │ ├── package-info.java │ │ ├── DaemonThreadFactory.java │ │ ├── ListenerRegistration.java │ │ ├── BriefLogFormatter.java │ │ └── ExponentialBackoff.java │ │ ├── script │ │ ├── ScriptException.java │ │ └── ScriptError.java │ │ ├── Monetary.java │ │ ├── PublicKey.java │ │ ├── ecc │ │ ├── NativeSecp256k1Util.java │ │ └── Secp256k1Context.java │ │ ├── address │ │ └── PrefixedChecksummedBytes.java │ │ ├── UnsafeByteArrayOutputStream.java │ │ ├── Address.java │ │ ├── PrivateKey.java │ │ └── VarInt.java └── test │ ├── resources │ └── org │ │ └── twostack │ │ └── bitcoin4j │ │ ├── block │ │ ├── block169482.dat │ │ ├── block227835.dat │ │ ├── block227836.dat │ │ ├── block363703.dat │ │ ├── block370661.dat │ │ ├── block383616.dat │ │ ├── block481815.dat │ │ ├── block481829.dat │ │ ├── first-100k-blocks.dat │ │ ├── block_testnet21066.dat │ │ ├── block_testnet32768.dat │ │ └── block_testnet700000.dat │ │ ├── sig_canonical.json │ │ ├── transaction │ │ ├── multi_input_local.json │ │ ├── tx_creation.json │ │ └── multi_input.json │ │ ├── sig_noncanonical.json │ │ └── LegacyAddressTestDataset.txt │ └── java │ └── org │ └── twostack │ └── bitcoin4j │ ├── transaction │ ├── TransactionOutputTest.java │ ├── TransactionInputTest.java │ └── SigHashTest.java │ ├── base58 │ ├── Base58DecodeCheckedInvalidChecksumTest.java │ ├── Base58DecodeToBigIntegerTest.java │ ├── Base58EncodeTest.java │ ├── Base58EncodeCheckedTest.java │ ├── Base58DecodeTest.java │ └── Base58DecodeCheckedTest.java │ ├── script │ ├── ScriptPatternTest.java │ ├── ScriptBuilderTest.java │ └── ScriptChunkTest.java │ ├── utils │ ├── TestUtil.java │ └── VarIntTest.java │ └── crypto │ ├── MnemonicCodeTest.java │ └── HDKeyDerivationTest.java ├── .github └── workflows │ └── gradle.yml ├── AUTHORS ├── gradlew.bat └── README.md /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'bitcoin4j' 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | *.class 4 | build 5 | .gradle 6 | 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twostack/bitcoin4j/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/params/AddressType.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.params; 2 | 3 | public enum AddressType { 4 | PUBKEY_HASH, SCRIPT_HASH 5 | } 6 | -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/block/block169482.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twostack/bitcoin4j/HEAD/src/test/resources/org/twostack/bitcoin4j/block/block169482.dat -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/block/block227835.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twostack/bitcoin4j/HEAD/src/test/resources/org/twostack/bitcoin4j/block/block227835.dat -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/block/block227836.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twostack/bitcoin4j/HEAD/src/test/resources/org/twostack/bitcoin4j/block/block227836.dat -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/block/block363703.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twostack/bitcoin4j/HEAD/src/test/resources/org/twostack/bitcoin4j/block/block363703.dat -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/block/block370661.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twostack/bitcoin4j/HEAD/src/test/resources/org/twostack/bitcoin4j/block/block370661.dat -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/block/block383616.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twostack/bitcoin4j/HEAD/src/test/resources/org/twostack/bitcoin4j/block/block383616.dat -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/block/block481815.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twostack/bitcoin4j/HEAD/src/test/resources/org/twostack/bitcoin4j/block/block481815.dat -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/block/block481829.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twostack/bitcoin4j/HEAD/src/test/resources/org/twostack/bitcoin4j/block/block481829.dat -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/params/NetworkType.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.params; 2 | 3 | public enum NetworkType { 4 | MAIN, TEST, REGTEST, SCALINGTEST 5 | } 6 | -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/block/first-100k-blocks.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twostack/bitcoin4j/HEAD/src/test/resources/org/twostack/bitcoin4j/block/first-100k-blocks.dat -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/block/block_testnet21066.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twostack/bitcoin4j/HEAD/src/test/resources/org/twostack/bitcoin4j/block/block_testnet21066.dat -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/block/block_testnet32768.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twostack/bitcoin4j/HEAD/src/test/resources/org/twostack/bitcoin4j/block/block_testnet32768.dat -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/block/block_testnet700000.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twostack/bitcoin4j/HEAD/src/test/resources/org/twostack/bitcoin4j/block/block_testnet700000.dat -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/params/NetworkAddressType.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.params; 2 | 3 | public enum NetworkAddressType { 4 | MAIN_PKH, MAIN_P2SH, TEST_PKH, TEST_P2SH 5 | } 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/exception/SigHashException.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.exception; 2 | 3 | public class SigHashException extends Exception{ 4 | public SigHashException(String message){ 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/exception/InvalidKeyException.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.exception; 2 | 3 | public class InvalidKeyException extends Exception{ 4 | public InvalidKeyException(String message){ 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/exception/TransactionException.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.exception; 2 | 3 | public class TransactionException extends Exception{ 4 | 5 | public TransactionException(String message){ 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/sig_canonical.json: -------------------------------------------------------------------------------- 1 | [ 2 | "300602010002010001", 3 | "3008020200ff020200ff01", 4 | "304402203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df0c022030b61dd36543125d56b9f9f3a1f9353189e5af33cdda8d77a5209aec03978fa001", 5 | "30450220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01", 6 | "3046022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01" 7 | ] 8 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/exception/PubKeyEncodingException.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.exception; 2 | 3 | import org.twostack.bitcoin4j.script.ScriptError; 4 | 5 | public class PubKeyEncodingException extends Exception{ 6 | 7 | ScriptError err; 8 | 9 | public PubKeyEncodingException() {super();} 10 | 11 | public PubKeyEncodingException(String message) {super(message);} 12 | 13 | public PubKeyEncodingException(ScriptError err, String message){ 14 | super(message); 15 | this.err = err; 16 | } 17 | 18 | public ScriptError getErr() { 19 | return err; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/exception/SignatureEncodingException.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.exception; 2 | 3 | import org.twostack.bitcoin4j.script.ScriptError; 4 | 5 | public class SignatureEncodingException extends Exception{ 6 | ScriptError err; 7 | 8 | public SignatureEncodingException() {super();} 9 | 10 | public SignatureEncodingException(String message){super(message);} 11 | 12 | public SignatureEncodingException(ScriptError err, String message){ 13 | super(message); 14 | this.err = err; 15 | 16 | } 17 | 18 | public ScriptError getErr() { 19 | return err; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Gradle 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle 3 | 4 | name: Java CI with Gradle 5 | 6 | on: 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up JDK 11 20 | uses: actions/setup-java@v2 21 | with: 22 | java-version: '11' 23 | distribution: 'adopt' 24 | - name: Grant execute permission for gradlew 25 | run: chmod +x gradlew 26 | - name: Build with Gradle 27 | run: ./gradlew build 28 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/P2SHUnlockBuilder.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.transaction; 2 | 3 | import org.twostack.bitcoin4j.script.Script; 4 | import org.twostack.bitcoin4j.script.ScriptError; 5 | import org.twostack.bitcoin4j.script.ScriptException; 6 | 7 | public class P2SHUnlockBuilder extends UnlockingScriptBuilder{ 8 | 9 | Script script; 10 | 11 | public P2SHUnlockBuilder(Script script){ 12 | if (script != null) { 13 | this.script = script; 14 | }else{ 15 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Invalid or malformed script"); 16 | } 17 | } 18 | 19 | @Override 20 | public Script getUnlockingScript() { 21 | return script; 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/crypto/HDDerivationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Matija Mazi. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.crypto; 18 | 19 | public class HDDerivationException extends RuntimeException { 20 | public HDDerivationException(String message) { 21 | super(message); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/transaction/TransactionOutputTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright by the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.transaction; 18 | 19 | import static org.junit.Assert.assertFalse; 20 | import static org.junit.Assert.assertTrue; 21 | 22 | public class TransactionOutputTest { 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/utils/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | /** 16 | * Formatting monetary amounts, representing exchange rates, a program for loading Bitcoin Core saved block files, 17 | * a class to control how bitcoinj uses threads and misc other utility classes that don't fit anywhere else. 18 | */ 19 | package org.twostack.bitcoin4j.utils; -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/exception/ProtocolException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.exception; 18 | 19 | @SuppressWarnings("serial") 20 | public class ProtocolException extends VerificationException { 21 | 22 | public ProtocolException(String msg) { 23 | super(msg); 24 | } 25 | 26 | public ProtocolException(Exception e) { 27 | super(e); 28 | } 29 | 30 | public ProtocolException(String msg, Exception e) { 31 | super(msg, e); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/DefaultLockBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Stephan M. February 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.twostack.bitcoin4j.transaction; 17 | 18 | import org.twostack.bitcoin4j.script.Script; 19 | 20 | public class DefaultLockBuilder extends LockingScriptBuilder{ 21 | 22 | public DefaultLockBuilder(Script script){ 23 | super(script); 24 | } 25 | 26 | public DefaultLockBuilder(){ 27 | super(); 28 | } 29 | 30 | @Override 31 | public Script getLockingScript() { 32 | return script; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/base58/Base58DecodeCheckedInvalidChecksumTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * Copyright 2014 Andreas Schildbach 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.twostack.bitcoin4j.base58; 19 | 20 | import org.junit.Test; 21 | import org.twostack.bitcoin4j.address.Base58; 22 | import org.twostack.bitcoin4j.exception.AddressFormatException; 23 | 24 | public class Base58DecodeCheckedInvalidChecksumTest { 25 | 26 | @Test(expected = AddressFormatException.InvalidChecksum.class) 27 | public void testDecodeChecked_invalidChecksum() { 28 | Base58.decodeChecked("4stwEBjT6FYyVW"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/LockingScriptBuilder.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2021 Stephan M. February 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.twostack.bitcoin4j.transaction; 18 | 19 | import org.twostack.bitcoin4j.script.Script; 20 | import org.twostack.bitcoin4j.script.ScriptBuilder; 21 | 22 | public abstract class LockingScriptBuilder { 23 | 24 | protected Script script; 25 | 26 | public abstract Script getLockingScript(); 27 | 28 | public LockingScriptBuilder(){ 29 | this.script = new ScriptBuilder().build(); 30 | } 31 | 32 | public LockingScriptBuilder(Script script){ 33 | this.script = script; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/base58/Base58DecodeToBigIntegerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * Copyright 2014 Andreas Schildbach 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.twostack.bitcoin4j.base58; 19 | 20 | import org.junit.Test; 21 | import org.twostack.bitcoin4j.address.Base58; 22 | 23 | import java.math.BigInteger; 24 | 25 | import static org.junit.Assert.assertEquals; 26 | 27 | public class Base58DecodeToBigIntegerTest { 28 | 29 | @Test 30 | public void testDecodeToBigInteger() { 31 | byte[] input = Base58.decode("129"); 32 | assertEquals(new BigInteger(1, input), Base58.decodeToBigInteger("129")); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/exception/SignatureDecodeException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright by the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.exception; 18 | 19 | public class SignatureDecodeException extends Exception { 20 | public SignatureDecodeException() { 21 | super(); 22 | } 23 | 24 | public SignatureDecodeException(String message) { 25 | super(message); 26 | } 27 | 28 | public SignatureDecodeException(Throwable cause) { 29 | super(cause); 30 | } 31 | 32 | public SignatureDecodeException(String message, Throwable cause) { 33 | super(message, cause); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/P2SHLockBuilder.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.transaction; 2 | 3 | import org.twostack.bitcoin4j.Utils; 4 | import org.twostack.bitcoin4j.script.*; 5 | 6 | import java.nio.ByteBuffer; 7 | 8 | public class P2SHLockBuilder extends LockingScriptBuilder{ 9 | 10 | ByteBuffer scriptHash; 11 | 12 | public P2SHLockBuilder(ByteBuffer scriptHash){ 13 | this.scriptHash = scriptHash; 14 | } 15 | 16 | public P2SHLockBuilder(Script script){ 17 | 18 | if (script != null){ 19 | byte[] byteBuffer = Utils.sha256hash160(script.getProgram()); 20 | 21 | this.scriptHash = ByteBuffer.wrap(byteBuffer); 22 | }else{ 23 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Invalid script or malformed script"); 24 | } 25 | } 26 | 27 | @Override 28 | public Script getLockingScript() { 29 | 30 | if (scriptHash == null){ 31 | return new ScriptBuilder().build(); 32 | } 33 | 34 | ScriptBuilder builder = new ScriptBuilder(); 35 | builder.op(ScriptOpCodes.OP_HASH160); 36 | builder.data(scriptHash.array()); 37 | builder.op(ScriptOpCodes.OP_EQUAL); 38 | 39 | return builder.build(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/script/ScriptException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.script; 18 | 19 | import org.twostack.bitcoin4j.exception.VerificationException; 20 | 21 | @SuppressWarnings("serial") 22 | public class ScriptException extends VerificationException { 23 | 24 | private final ScriptError err; 25 | 26 | public ScriptException(ScriptError err, String msg) { 27 | super(msg); 28 | this.err = err; 29 | } 30 | 31 | public ScriptException(ScriptError err, String msg, Exception e) { 32 | super(msg, e); 33 | this.err = err; 34 | } 35 | 36 | public ScriptError getError() { 37 | return err; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/DefaultUnlockBuilder.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2021 Stephan M. February 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.twostack.bitcoin4j.transaction; 18 | 19 | import org.twostack.bitcoin4j.script.Script; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | public class DefaultUnlockBuilder extends UnlockingScriptBuilder { 25 | 26 | List signatures = new ArrayList<>(); 27 | 28 | public DefaultUnlockBuilder(){ 29 | super(); 30 | } 31 | 32 | public DefaultUnlockBuilder(Script script){ 33 | super(script); 34 | } 35 | 36 | @Override 37 | public Script getUnlockingScript() { 38 | return script; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/Monetary.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Andreas Schildbach 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j; 18 | 19 | import java.io.Serializable; 20 | 21 | /** 22 | * Classes implementing this interface represent a monetary value, such as a Bitcoin or fiat amount. 23 | */ 24 | public interface Monetary extends Serializable { 25 | 26 | /** 27 | * @return the absolute value of exponent of the value of a "smallest unit" in scientific notation. For Bitcoin, a 28 | * satoshi is worth 1E-8 so this would be 8. 29 | */ 30 | int smallestUnitExponent(); 31 | 32 | /** 33 | * @return the number of "smallest units" of this monetary value. For Bitcoin, this would be the number of satoshis. 34 | */ 35 | long getValue(); 36 | 37 | int signum(); 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/TransactionOption.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2021 Stephan M. February 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.twostack.bitcoin4j.transaction; 18 | 19 | public enum TransactionOption { 20 | 21 | // When serializing the transaction to hexadecimal it is possible 22 | // to selectively disable some checks. See [Transaction.serialize()] 23 | // Disables all checks 24 | DISABLE_ALL, 25 | 26 | /// Disables checking if the transaction spends more bitcoins than the sum of the input amounts 27 | DISABLE_MORE_OUTPUT_THAN_INPUT, 28 | 29 | /// Disables checking for fees that are too large 30 | DISABLE_LARGE_FEES, 31 | 32 | /// Disables checking if there are no outputs that are dust amounts 33 | DISABLE_DUST_OUTPUTS, 34 | 35 | /// Disables checking if all inputs are fully signed 36 | DISABLE_FULLY_SIGNED 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/transaction/TransactionInputTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright by the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.transaction; 18 | 19 | import org.junit.Test; 20 | import org.twostack.bitcoin4j.Utils; 21 | 22 | import java.io.IOException; 23 | 24 | import static org.junit.Assert.assertArrayEquals; 25 | 26 | public class TransactionInputTest { 27 | 28 | final static CharSequence txInputHex = "5884e5db9de218238671572340b207ee85b628074e7e467096c267266baf77a40000000000ffffffff"; 29 | 30 | @Test 31 | public void canSerializeInput() throws IOException { 32 | 33 | byte[] inputBytes = Utils.HEX.decode(txInputHex); 34 | TransactionInput txInput = TransactionInput.fromByteArray(inputBytes); 35 | 36 | byte[] serializedBytes = txInput.serialize(); 37 | 38 | assertArrayEquals(inputBytes, serializedBytes); 39 | } 40 | 41 | @Test 42 | public void canDeserializeInput(){ 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/utils/DaemonThreadFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright by the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.utils; 18 | 19 | import javax.annotation.Nonnull; 20 | import javax.annotation.Nullable; 21 | import java.util.concurrent.Executors; 22 | import java.util.concurrent.ThreadFactory; 23 | 24 | /** Thread factory whose threads are marked as daemon and won't prevent process exit. */ 25 | public class DaemonThreadFactory implements ThreadFactory { 26 | @Nullable private final String name; 27 | 28 | public DaemonThreadFactory(@Nullable String name) { 29 | this.name = name; 30 | } 31 | 32 | public DaemonThreadFactory() { 33 | this(null); 34 | } 35 | 36 | @Override 37 | public Thread newThread(@Nonnull Runnable runnable) { 38 | Thread thread = Executors.defaultThreadFactory().newThread(runnable); 39 | thread.setDaemon(true); 40 | if (name != null) 41 | thread.setName(name); 42 | return thread; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/PublicKey.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2021 Stephan M. February 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.twostack.bitcoin4j; 18 | 19 | public class PublicKey { 20 | 21 | 22 | private ECKey key; 23 | 24 | //FIXME: hide the constructor for now to force factory method usage 25 | private PublicKey(ECKey key){ 26 | this.key = key; 27 | } 28 | 29 | public static PublicKey fromHex(String encoded) { 30 | byte[] pubkeyBytes = Utils.HEX.decode(encoded); 31 | 32 | return new PublicKey(ECKey.fromPublicOnly(pubkeyBytes)); 33 | } 34 | 35 | public static PublicKey fromBytes(byte[] pubkeyBytes){ 36 | return new PublicKey(ECKey.fromPublicOnly(pubkeyBytes)); 37 | } 38 | 39 | public byte[] getPubKeyHash(){ 40 | return key.getPubKeyHash(); 41 | } 42 | 43 | public byte[] getPubKeyBytes(){ 44 | return key.getPubKey(); 45 | } 46 | 47 | public String getPubKeyHex(){ 48 | return key.getPublicKeyAsHex(); 49 | } 50 | 51 | public ECKey getKey() { 52 | return key; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/UnlockingScriptBuilder.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2021 Stephan M. February 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.twostack.bitcoin4j.transaction; 18 | 19 | import org.twostack.bitcoin4j.script.Script; 20 | import org.twostack.bitcoin4j.script.ScriptBuilder; 21 | 22 | import java.util.ArrayList; 23 | import java.util.Collections; 24 | import java.util.List; 25 | 26 | public abstract class UnlockingScriptBuilder { 27 | 28 | List signatures = new ArrayList<>(); 29 | 30 | protected Script script; 31 | 32 | public UnlockingScriptBuilder(Script script){ 33 | this.script = script; 34 | } 35 | 36 | public UnlockingScriptBuilder(){ 37 | this.script = new ScriptBuilder().build(); 38 | } 39 | 40 | public abstract Script getUnlockingScript(); 41 | 42 | public List getSignatures() { 43 | return Collections.unmodifiableList(signatures); 44 | } 45 | 46 | public void addSignature(TransactionSignature signature) { 47 | this.signatures.add(signature); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/SigHashType.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2021 Stephan M. February 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.twostack.bitcoin4j.transaction; 18 | 19 | public enum SigHashType { 20 | ALL(1), 21 | NONE(2), 22 | SINGLE(3), 23 | FORKID (0x40), 24 | ANYONECANPAY(0x80), // Caution: Using this type in isolation is non-standard. Treated similar to ANYONECANPAY_ALL. 25 | ANYONECANPAY_ALL(0x81), 26 | ANYONECANPAY_NONE(0x82), 27 | ANYONECANPAY_SINGLE(0x83), 28 | UNSET(0); // Caution: Using this type in isolation is non-standard. Treated similar to ALL. 29 | 30 | public final int value; 31 | 32 | /** 33 | * @param value 34 | */ 35 | private SigHashType(final int value) { 36 | this.value = value; 37 | } 38 | 39 | /** 40 | * @return the value as a byte 41 | */ 42 | public byte byteValue() { 43 | return (byte) this.value; 44 | } 45 | 46 | public static boolean hasValue(int value){ 47 | 48 | for (SigHashType t : values()){ 49 | if (t.value == value) 50 | return true; 51 | } 52 | 53 | return false; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/transaction/multi_input_local.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "height": 1433834, 4 | "value": 500000000, 5 | "tx_pos": 0, 6 | "raw_tx": "0200000001f4145c67f9678e55584c9e258b3de751f74d1ceebd0cdfa7391fef8945e650a300000000484730440220717b3cc7930b5b7114e92dc239c27aa69314898aae642be43a731b696cddd0100220043d63d6b0f7b16cca5bcaed722ad80ec36480c112c7c6c34e4fe2b4f0837ba841feffffff020065cd1d000000001976a914191f99293aedd9f66e090e296abe2c64cabdbc5788ac80587307000000001976a914cad75dd4a8ea76c18ad5e561afd013daa4a8d0ec88ac6a020000", 7 | "tx_hash": "9dc51e14a93ef538affe675200aeec15aedc0378c093074cf302f4d731eb484f" 8 | }, 9 | { 10 | "height": 1433834, 11 | "value": 700000000, 12 | "tx_pos": 0, 13 | "tx_hash": "d2cbb85329f1f14f94e028edb8d2bc21cb3ffe9aed8b58f8741571580a186a38", 14 | "raw_tx": "0200000001ddbb28b78fc3f6501afff0bbff1add8aea9301d906a706362b9ac9650418f6050000000047463043021f1f31214b5fa7deb37a72bfb4de421048e338669eec554d5dd7edbe3af337e302200e58d8a7964d0d26319950fa3ed3599dc9e338fea83577c207e9f788c77b604341feffffff020027b929000000001976a914191f99293aedd9f66e090e296abe2c64cabdbc5788acc054c820000000001976a91468bda6c59f5211caaefd49d69e45c56d88b4cd3788ac6a020000" 15 | }, 16 | { 17 | "height": 1433834, 18 | "value": 600000000, 19 | "tx_pos": 1, 20 | "raw_tx": "02000000011a44b1703870432cb26a89a269b1bd546b3ff5fdc7775d5dda07154c897c878a000000004847304402205ebe801f4a5a693a607eac50d217653271295df3421b3c2c502739da04ecd2e1022019c018c1cd8f8692872b8f7e8ab61bc912b32e22f57ab680ccd7d4d8a4c97ad941feffffff0280777d01000000001976a914a99d5811b500ba6dec61dc4bf95fa96f4d610e6688ac0046c323000000001976a914191f99293aedd9f66e090e296abe2c64cabdbc5788ac6a020000", 21 | "tx_hash": "67e7555620688f285b76f7cb4698679ffbd006029bd9c51d36d153b8bdbeb377" 22 | } 23 | ] 24 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/utils/ListenerRegistration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.utils; 18 | 19 | import java.util.List; 20 | import java.util.concurrent.Executor; 21 | 22 | import static com.google.common.base.Preconditions.checkNotNull; 23 | 24 | /** 25 | * A simple wrapper around a listener and an executor, with some utility methods. 26 | */ 27 | public class ListenerRegistration { 28 | public final T listener; 29 | public final Executor executor; 30 | 31 | public ListenerRegistration(T listener, Executor executor) { 32 | this.listener = checkNotNull(listener); 33 | this.executor = checkNotNull(executor); 34 | } 35 | 36 | /** Returns true if the listener was removed, else false. */ 37 | public static boolean removeFromList(T listener, List> list) { 38 | checkNotNull(listener); 39 | 40 | ListenerRegistration item = null; 41 | for (ListenerRegistration registration : list) { 42 | if (registration.listener == listener) { 43 | item = registration; 44 | break; 45 | } 46 | } 47 | return item != null && list.remove(item); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/ecc/NativeSecp256k1Util.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2016 the libsecp256k1 contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.ecc; 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | public class NativeSecp256k1Util { 23 | 24 | private static final Logger log = LoggerFactory.getLogger(NativeSecp256k1Util.class); 25 | 26 | public static void assertEquals(int val, int val2, String message) throws AssertFailException { 27 | if (val != val2) 28 | throw new AssertFailException("FAIL: " + message); 29 | } 30 | 31 | public static void assertEquals(boolean val, boolean val2, String message) throws AssertFailException { 32 | if (val != val2) 33 | throw new AssertFailException("FAIL: " + message); 34 | else 35 | log.debug("PASS: " + message); 36 | } 37 | 38 | public static void assertEquals(String val, String val2, String message) throws AssertFailException { 39 | if (!val.equals(val2)) 40 | throw new AssertFailException("FAIL: " + message); 41 | else 42 | log.debug("PASS: " + message); 43 | } 44 | 45 | public static class AssertFailException extends Exception { 46 | public AssertFailException(String message) { 47 | super(message); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/P2PKLockBuilder.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.transaction; 2 | 3 | import org.twostack.bitcoin4j.PublicKey; 4 | import org.twostack.bitcoin4j.script.*; 5 | 6 | import java.util.List; 7 | 8 | import static org.twostack.bitcoin4j.script.ScriptOpCodes.OP_CHECKSIG; 9 | 10 | public class P2PKLockBuilder extends LockingScriptBuilder { 11 | 12 | private PublicKey signerPubkey; 13 | 14 | public P2PKLockBuilder(PublicKey publicKey){ 15 | this.signerPubkey = publicKey; 16 | } 17 | 18 | public P2PKLockBuilder(Script script) { 19 | parse(script); 20 | } 21 | 22 | private void parse(Script script) { 23 | 24 | if (script == null) { 25 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Invalid Script or Malformed Script."); 26 | } 27 | 28 | if (script != null) { 29 | 30 | List chunkList = script.getChunks(); 31 | 32 | if (chunkList.size() != 2) { 33 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Wrong number of data elements for P2PK Locking Script"); 34 | } 35 | 36 | if (chunkList.get(1).opcode != ScriptOpCodes.OP_CHECKSIG) { 37 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Malformed P2PK Locking Script. Mismatched OP_CODES."); 38 | } 39 | 40 | signerPubkey = PublicKey.fromBytes(chunkList.get(0).data); 41 | } 42 | } 43 | 44 | @Override 45 | public Script getLockingScript() { 46 | 47 | if (this.signerPubkey == null) { 48 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Missing Public Key. Can't construct the script."); 49 | } 50 | 51 | ScriptBuilder builder = new ScriptBuilder(); 52 | builder.data(this.signerPubkey.getPubKeyBytes()); 53 | builder.op(OP_CHECKSIG); 54 | 55 | return builder.build(); 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/base58/Base58EncodeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * Copyright 2014 Andreas Schildbach 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.twostack.bitcoin4j.base58; 19 | 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.junit.runners.Parameterized; 23 | import org.twostack.bitcoin4j.address.Base58; 24 | 25 | import java.math.BigInteger; 26 | import java.util.Arrays; 27 | import java.util.Collection; 28 | 29 | import static org.junit.Assert.assertEquals; 30 | import static org.junit.runners.Parameterized.Parameters; 31 | 32 | @RunWith(Parameterized.class) 33 | public class Base58EncodeTest { 34 | 35 | private byte[] input; 36 | private String expected; 37 | 38 | public Base58EncodeTest(byte[] input, String expected) { 39 | this.input = input; 40 | this.expected = expected; 41 | } 42 | 43 | @Parameters 44 | public static Collection parameters() { 45 | return Arrays.asList(new Object[][]{ 46 | {"Hello World".getBytes(), "JxF12TrwUP45BMd"}, 47 | {BigInteger.valueOf(3471844090L).toByteArray(), "16Ho7Hs"}, 48 | {new byte[1], "1"}, 49 | {new byte[7], "1111111"}, 50 | {new byte[0], ""} 51 | }); 52 | } 53 | 54 | @Test 55 | public void testEncode() { 56 | assertEquals(expected, Base58.encode(input)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/base58/Base58EncodeCheckedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * Copyright 2014 Andreas Schildbach 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.twostack.bitcoin4j.base58; 19 | 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.junit.runners.Parameterized; 23 | import org.junit.runners.Parameterized.Parameters; 24 | import org.twostack.bitcoin4j.address.Base58; 25 | import org.twostack.bitcoin4j.address.LegacyAddress; 26 | 27 | import java.util.Arrays; 28 | import java.util.Collection; 29 | 30 | import static org.junit.Assert.assertEquals; 31 | 32 | @RunWith(Parameterized.class) 33 | public class Base58EncodeCheckedTest { 34 | 35 | private int version; 36 | private byte[] input; 37 | private String expected; 38 | 39 | @Parameters 40 | public static Collection parameters() { 41 | return Arrays.asList(new Object[][]{ 42 | {111, new byte[LegacyAddress.LENGTH], "mfWxJ45yp2SFn7UciZyNpvDKrzbhyfKrY8"}, 43 | {128, new byte[32], "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAbuatmU"} 44 | }); 45 | } 46 | 47 | public Base58EncodeCheckedTest(int version, byte[] input, String expected) { 48 | this.version = version; 49 | this.input = input; 50 | this.expected = expected; 51 | } 52 | 53 | @Test 54 | public void testEncode() { 55 | assertEquals(expected, Base58.encodeChecked(version, input)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/ecc/Secp256k1Context.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2016 the libsecp256k1 contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.ecc; 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | import java.security.AccessControlException; 23 | 24 | /** 25 | * This class holds the context reference used in native methods to handle ECDSA operations. 26 | */ 27 | public class Secp256k1Context { 28 | 29 | private static final boolean enabled; // true if the library is loaded 30 | private static final long context; // ref to pointer to context obj 31 | 32 | private static final Logger log = LoggerFactory.getLogger(Secp256k1Context.class); 33 | 34 | static { // static initializer 35 | boolean isEnabled = true; 36 | long contextRef = -1; 37 | try { 38 | System.loadLibrary("secp256k1"); 39 | contextRef = secp256k1_init_context(); 40 | } catch (UnsatisfiedLinkError | AccessControlException e) { 41 | log.debug(e.toString()); 42 | isEnabled = false; 43 | } 44 | enabled = isEnabled; 45 | context = contextRef; 46 | } 47 | 48 | public static boolean isEnabled() { 49 | return enabled; 50 | } 51 | 52 | public static long getContext() { 53 | if (!enabled) 54 | return -1; // sanity check 55 | return context; 56 | } 57 | 58 | private static native long secp256k1_init_context(); 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/exception/MnemonicException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Ken Sedgwick 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.exception; 18 | 19 | /** 20 | * Exceptions thrown by the MnemonicCode module. 21 | */ 22 | @SuppressWarnings("serial") 23 | public class MnemonicException extends Exception { 24 | public MnemonicException() { 25 | super(); 26 | } 27 | 28 | public MnemonicException(String msg) { 29 | super(msg); 30 | } 31 | 32 | /** 33 | * Thrown when an argument to MnemonicCode is the wrong length. 34 | */ 35 | public static class MnemonicLengthException extends MnemonicException { 36 | public MnemonicLengthException(String msg) { 37 | super(msg); 38 | } 39 | } 40 | 41 | /** 42 | * Thrown when a list of MnemonicCode words fails the checksum check. 43 | */ 44 | public static class MnemonicChecksumException extends MnemonicException { 45 | public MnemonicChecksumException() { 46 | super(); 47 | } 48 | } 49 | 50 | /** 51 | * Thrown when a word is encountered which is not in the MnemonicCode's word list. 52 | */ 53 | public static class MnemonicWordException extends MnemonicException { 54 | /** Contains the word that was not found in the word list. */ 55 | public final String badWord; 56 | 57 | public MnemonicWordException(String badWord) { 58 | super(); 59 | this.badWord = badWord; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/P2MSUnlockBuilder.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.transaction; 2 | 3 | import org.twostack.bitcoin4j.exception.SignatureDecodeException; 4 | import org.twostack.bitcoin4j.script.*; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class P2MSUnlockBuilder extends UnlockingScriptBuilder{ 10 | 11 | /* 12 | Default constructor won't init signatures. 13 | Signatures are injected as part of signing process 14 | */ 15 | public P2MSUnlockBuilder(){ 16 | super(); 17 | } 18 | 19 | public P2MSUnlockBuilder(List signatures){ 20 | super(); 21 | this.signatures = new ArrayList<>(signatures); //copy signature list 22 | } 23 | 24 | public P2MSUnlockBuilder(Script script){ 25 | parse(script) ; 26 | } 27 | 28 | private void parse(Script script){ 29 | 30 | if (script.getChunks().size() > 0){ 31 | 32 | List chunks = script.getChunks(); 33 | 34 | try { 35 | 36 | for (int i = 1; i < chunks.size(); i++) { 37 | signatures.add(TransactionSignature.fromTxFormat(chunks.get(i).data)); 38 | } 39 | 40 | }catch(SignatureDecodeException ex){ 41 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, 42 | "Script parsing failed. Invalid signatures detected."); 43 | } 44 | 45 | }else{ 46 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, 47 | "Invalid script or malformed script"); 48 | } 49 | 50 | } 51 | 52 | @Override 53 | public Script getUnlockingScript() { 54 | 55 | ScriptBuilder builder = new ScriptBuilder(); 56 | builder.op(ScriptOpCodes.OP_0); //push a value to stack first. this will be ignored by multisig bug, but is required(by the bug). 57 | 58 | for (TransactionSignature signature : signatures) { 59 | builder.data(signature.getSignatureBytes()); 60 | } 61 | 62 | return builder.build(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Aaron Voisine 2 | Adam Mackler 3 | Alexander Lolis 4 | Alex Taylor 5 | Alex Voloshko 6 | Alok Menghrajani 7 | Alon Muroch 8 | Amichai Rothman 9 | Andreas Schildbach 10 | andrewtoth 11 | Bas van Schaik 12 | Bennett Hoffman 13 | BigAdam2005 14 | Bo-Ye 15 | Carlos Lopez-Camey 16 | Carsten Otto 17 | Chang Ming 18 | Chris 19 | cyberzac 20 | Daniel James 21 | Dave Collins 22 | David Kingsbury 23 | David Wilson (dcw312) 24 | dexX7 25 | Diego Basch 26 | elbandi 27 | eleetas 28 | En-Ran Zhou 29 | Eric Winer 30 | Erik Tierney 31 | Fireduck 32 | freak 33 | Gary Rowe 34 | Giannis Dzegoutanis 35 | Gitju 36 | Giuseppe Raveduto 37 | Glenn Marien 38 | GreenAddress 39 | Greg Laun 40 | gubatron 41 | Harald Hoyer 42 | Jakob Stuber 43 | Jameson Lopp 44 | Jan Vornberger 45 | Jarl Fransson 46 | Jean-Pierre Rupp 47 | Jim Burton 48 | Jiri Peinlich 49 | Johnathan 50 | John L. Jegutanis 51 | Johny George 52 | Jonathan Cross 53 | Jon Griffiths 54 | Jonny Heggheim 55 | Justas Dobiliauskas 56 | Kalpesh Parmar 57 | Ken Sedgwick 58 | Kevin Greene 59 | Kirill Vlasov 60 | Kosta Korenkov 61 | kushti 62 | langerhans 63 | Loco 64 | Manfred Karrer 65 | Marc-André Tremblay 66 | Martin Zachrison 67 | matija.mazi@gmail.com 68 | Matt Bogosian 69 | Matt Corallo 70 | Matthew Leon 71 | Matthew Shaylor 72 | Michael Bell 73 | Michael Bumann 74 | Mike Hearn 75 | Mike Rosseel 76 | Miron Cuperman 77 | monk 78 | Mora Zyx 79 | mruddy 80 | Nelson Melina 81 | Nicola Atzei 82 | ollekullberg 83 | Oscar Guindzberg 84 | Pavol Rusnak 85 | peacekeeper 86 | Peter Dettman 87 | Peter Stockli 88 | Peter Todd 89 | Philip Whitehouse 90 | Piotr Włodarek 91 | Richard Green 92 | Richard Green (ragmondo) 93 | Robin Owens 94 | Ronald Hoffman (ScripterRon) 95 | Ross Nicoll 96 | Saulius Beinorius 97 | Sean Gilligan 98 | Sebastian Ortega 99 | Simon de la Rouviere 100 | Simon Vermeersch 101 | Stephan February 102 | Stephan Oeste 103 | Stephen Reed 104 | Thomas König 105 | Tomasz Ludek 106 | troggy 107 | Tyler Houlihan 108 | Willem Noort 109 | Will Shackleton 110 | Wojciech Langiewicz 111 | Xiaofeng Guo 112 | Ximo Guanter 113 | zkejid 114 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/P2PKUnlockBuilder.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.transaction; 2 | 3 | import org.twostack.bitcoin4j.exception.SignatureDecodeException; 4 | import org.twostack.bitcoin4j.script.*; 5 | 6 | import java.util.List; 7 | 8 | public class P2PKUnlockBuilder extends UnlockingScriptBuilder{ 9 | 10 | public P2PKUnlockBuilder(TransactionSignature signature){ 11 | addSignature(signature); 12 | } 13 | 14 | public P2PKUnlockBuilder(Script script){ 15 | parse(script); 16 | } 17 | 18 | @Override 19 | public Script getUnlockingScript() { 20 | 21 | List signatures = getSignatures(); 22 | 23 | TransactionSignature signature = null; 24 | if (!signatures.isEmpty()) { 25 | signature = getSignatures().get(0); 26 | } 27 | 28 | if (signature == null){ 29 | return new ScriptBuilder().build(); //return empty script; otherwise we will barf on early serialize (prior to signing) 30 | } 31 | 32 | try { 33 | return new ScriptBuilder().data(signature.toTxFormat()).build(); 34 | }catch(Exception ex){ 35 | System.out.println(ex.getMessage()); 36 | ex.printStackTrace(); //FIXME: Handle more gracefully 37 | return new ScriptBuilder().build(); 38 | } 39 | 40 | } 41 | 42 | private void parse(Script script) { 43 | 44 | if (script == null){ 45 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Script value cannot be null."); 46 | } 47 | 48 | List chunkList = script.getChunks(); 49 | 50 | if (chunkList.size() != 1){ 51 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Wrong number of data elements for P2PK ScriptSig"); 52 | } 53 | 54 | byte[] sig = chunkList.get(0).data; 55 | 56 | try { 57 | signatures.add(TransactionSignature.fromTxFormat(sig)); 58 | }catch (SignatureDecodeException ex){ 59 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Script signature is invalid : " + ex.getMessage()); 60 | } 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/sig_noncanonical.json: -------------------------------------------------------------------------------- 1 | [ 2 | "non-hex strings are ignored", 3 | 4 | "too short:", "30050201FF020001", 5 | "too long:", "30470221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 6 | "hashtype:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed11", 7 | "type:", "314402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 8 | "total length:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 9 | "S len oob:", "301F01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb101", 10 | "R+S:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed0001", 11 | 12 | "R type:", "304401205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 13 | "R len = 0:", "3024020002202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 14 | "R<0:", "304402208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 15 | "R padded:", "30450221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 16 | 17 | 18 | "S type:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610501202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 19 | "S len = 0:", "302402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105020001", 20 | "S<0:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", 21 | "S padded:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01" 22 | ] 23 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/base58/Base58DecodeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * Copyright 2014 Andreas Schildbach 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.twostack.bitcoin4j.base58; 19 | 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.junit.runners.Parameterized; 23 | import org.twostack.bitcoin4j.address.Base58; 24 | import org.twostack.bitcoin4j.exception.AddressFormatException; 25 | 26 | import java.util.Arrays; 27 | import java.util.Collection; 28 | 29 | import static org.junit.Assert.assertArrayEquals; 30 | import static org.junit.Assert.assertEquals; 31 | import static org.junit.runners.Parameterized.Parameters; 32 | 33 | @RunWith(Parameterized.class) 34 | public class Base58DecodeTest { 35 | 36 | private String input; 37 | private byte[] expected; 38 | 39 | public Base58DecodeTest(String input, byte[] expected) { 40 | this.input = input; 41 | this.expected = expected; 42 | } 43 | 44 | @Parameters 45 | public static Collection parameters() { 46 | return Arrays.asList(new Object[][]{ 47 | {"JxF12TrwUP45BMd", "Hello World".getBytes()}, 48 | {"1", new byte[1]}, 49 | {"1111", new byte[4]} 50 | }); 51 | } 52 | 53 | @Test 54 | public void testDecode() { 55 | byte[] actualBytes = Base58.decode(input); 56 | assertArrayEquals(input, actualBytes, expected); 57 | } 58 | 59 | @Test 60 | public void testDecode_emptyString() { 61 | assertEquals(0, Base58.decode("").length); 62 | } 63 | 64 | @Test(expected = AddressFormatException.class) 65 | public void testDecode_invalidBase58() { 66 | Base58.decode("This isn't valid base58"); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/LegacyAddressTestDataset.txt: -------------------------------------------------------------------------------- 1 | 1Dorian4RoXcnBv9hnQ4Y2C1an6NJ4UrjX,1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P 2 | 12prgkB2jumVVh1iSQaSLqroe81RyaqkyR,1ArPkmHt15fYrNJ8br7GYVduZiugtSfAC8 3 | 13G22VU8uXCsmh2PZ8Vh8CnWUtkz1mpDnY,1QJ3i7HhMX9ymKNJU8szirD57VyCUop8rv 4 | 1CK6KHY6MHgYvmRQ4PAafKYDrg1ejbH1cE,1DWsmHpyELq51pYUxCjBjwBpt4yyXfEjif 5 | 1CTC2u5B6DhBe8LkaSnZvxNeScrBByYiFv,1H1hGnwaQed7JPPqYgfYR2HqLyGfMnMZ92 6 | 1GFpf1cAgCneQrLHn1AWL95FXZ3196gLbi,1L59Gh2FUk6bsG7t7LzGuti3PwMT6vKDta 7 | 12vnBzWDDuftQYqjSbiYMuT66KmAGsXYYE,1PLtsSnkabRETVYRvyFUSAKTHbtL7FZvgY 8 | 19pH85mQvmLn45xFj3K3or3EaijUjMy4xj,1PsqoEpNo9Yb2PNpc4PbfhQuHzxz1JCK34 9 | 1BPuMoYqgE3kYL76qAF6SrL2nJMtyKCbcM,1KpJZ9Q6tj2yegQAzLUmmov72d1pATE9Uu 10 | 1C1mCxRukix1KfegAY5zQQJV7samAciZpv,1Cudf98s16kW7152TwVsidYPhrPiYwLmJR 11 | 1J962fubMgq1YNGdT7EVMY91A1ULh9s9Ji,1QA74FEhzhLi23pVZjGQ2yWSGaep2Go5pq 12 | 12i7xva6bNNovaXW9a869w4Chze9VnvZjN,1PuoxiYCmsady21q6DSCNpwdNDQs1yujcG 13 | 16fFb8vPAQ4RPjtAfkQdHMpoTognrnTzs7,1KMVb5vJqD1ceQSHqUczFHHTVmm1v9rCEH 14 | 19frvQBjDhYnv9qjsC6YQs9nxfPCuFRsFe,1MTxMFJtCPuLHmnG7Ecef28su5DPxbaep5 15 | 17XrM9u3Edkh1PR8GpX5kfNZLn1JmrxGH7,1LfzzJ5EGpR81sxcbHVkcNvVsSDt6ZFJsz 16 | 1Ke11ARCEN6ynFtPdrTdFPGs1LQ4ukugDi,1Nv9scQTGdijZhHsWbbJf3kY1dZZ6sFJ1u 17 | 14xLHSd2vLMSSe7RLjUw6xtyLQCVSq8Mpa,1NKLb68QACKUqtGiwSN5W9znW5RZFCnbYV 18 | 1BjmkScvLX8kFn9FqtRDn79vfjhxjnW2ap,1EWyYmfyv7PvLz4DsCyWZf1zhavskfJqGG 19 | 16vi5dxVZXMRzF9Pt2EHDSMipYeePmQCyJ,1LvCnrgKryx7QEbsaPT9NJb1S8xMi8nWDi 20 | 13TdqLm25WgZw5NwjmYfdrRLRfob26GsM5,13apxjFiTBvqQxyFxPk7MCFTzAKgjaX6R4 21 | 1EK7ZHeh13wQG4b3z8wF423xbxT6HydR5i,1JK8voQbxSbGqJ2mShaVVepRKZ6xMvkJk8 22 | 13w8xV2XK5BX3rVLm5avvoAEf1JvBmwF2r,15xgB2X1hj7F2Ek2V3YfajvCrp2PbuSmMC 23 | 1K6PRbv68NBzcmMx3PSTms2DNvWjvX5yNg,1KHn81uJcVxcEeFTG5w78i2Pz4dtkeD78c 24 | 1AerGGVb9byLp1WK4r88f9wwGeM5YFQyfz,1Fn9WHnLe2CdA1aZCZbTAYnjzkD7mTL4LT 25 | 1ELt4mSqm5hHnQ5k8WQRG75aEdEWCJ1oyc,1F3tWDBPqjPbbCVDJEN3cv3x7hDrbkuXze 26 | 144Za3x1HSN4UtAqCP2Ym8xRsXkt95A8AL,1NURJdpmh15ostB6kweuummHRxgyMHWhi6 27 | 1K6PRbv68NBzcmMx3PSTms2DNvWjvX5yNg,1KHn81uJcVxcEeFTG5w78i2Pz4dtkeD78c 28 | 1AerGGVb9byLp1WK4r88f9wwGeM5YFQyfz,1Fn9WHnLe2CdA1aZCZbTAYnjzkD7mTL4LT 29 | 1ELt4mSqm5hHnQ5k8WQRG75aEdEWCJ1oyc,1F3tWDBPqjPbbCVDJEN3cv3x7hDrbkuXze 30 | 144Za3x1HSN4UtAqCP2Ym8xRsXkt95A8AL,1NURJdpmh15ostB6kweuummHRxgyMHWhi6 31 | 14NGL5LYhwkWREpeo2AMWU6HgbDfdqAuZC,1GMyyYHKC3RKqmjixxxoHnsDJ46hBsQbfS 32 | 17kuSgebpmoA8kbKQaiaokCBbWnteDtL27,19PUE9SnfhxoCp42eQCmDbWtqrLXat8sh2 33 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/crypto/EncryptedData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jim Burton. 3 | * 4 | * Licensed under the MIT license (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://opensource.org/licenses/mit-license.php 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.crypto; 18 | 19 | import java.util.Arrays; 20 | import java.util.Objects; 21 | 22 | /** 23 | *

An instance of EncryptedData is a holder for an initialization vector and encrypted bytes. It is typically 24 | * used to hold encrypted private key bytes.

25 | * 26 | *

The initialisation vector is random data that is used to initialise the AES block cipher when the 27 | * private key bytes were encrypted. You need these for decryption.

28 | */ 29 | public final class EncryptedData { 30 | public final byte[] initialisationVector; 31 | public final byte[] encryptedBytes; 32 | 33 | public EncryptedData(byte[] initialisationVector, byte[] encryptedBytes) { 34 | this.initialisationVector = Arrays.copyOf(initialisationVector, initialisationVector.length); 35 | this.encryptedBytes = Arrays.copyOf(encryptedBytes, encryptedBytes.length); 36 | } 37 | 38 | @Override 39 | public boolean equals(Object o) { 40 | if (this == o) return true; 41 | if (o == null || getClass() != o.getClass()) return false; 42 | EncryptedData other = (EncryptedData) o; 43 | return Arrays.equals(encryptedBytes, other.encryptedBytes) && Arrays.equals(initialisationVector, other.initialisationVector); 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return Objects.hash(Arrays.hashCode(encryptedBytes), Arrays.hashCode(initialisationVector)); 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return "EncryptedData [initialisationVector=" + Arrays.toString(initialisationVector) 54 | + ", encryptedPrivateKey=" + Arrays.toString(encryptedBytes) + "]"; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/UnspendableDataLockBuilder.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.transaction; 2 | 3 | import org.twostack.bitcoin4j.script.*; 4 | 5 | import java.nio.ByteBuffer; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class UnspendableDataLockBuilder extends LockingScriptBuilder{ 10 | 11 | List dataList = new ArrayList(); 12 | 13 | 14 | public UnspendableDataLockBuilder(List buffers){ 15 | this.dataList = buffers; 16 | } 17 | 18 | public UnspendableDataLockBuilder(Script script){ 19 | parse(script); 20 | } 21 | 22 | /** 23 | * Deserialize an OP_RETURN data output 24 | * 25 | * The OP_RETURN data output is to have the format: 26 | * 27 | * OP_FALSE OP_RETURN [data 1] [data 2] ... [data n] 28 | * 29 | */ 30 | private void parse(Script script){ 31 | 32 | if (script != null && script.getProgram().length != 0){ 33 | 34 | List chunks = script.getChunks(); 35 | if (chunks.get(0).opcode == ScriptOpCodes.OP_FALSE 36 | && chunks.get(1).opcode == ScriptOpCodes.OP_RETURN){ 37 | 38 | for (int i = 2; i < chunks.size(); i++){ 39 | if (chunks.get(i).opcode > ScriptOpCodes.OP_PUSHDATA4) { 40 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, 41 | "Only data pushes are allowed here. Consider making a custom LockingScriptBuilder."); 42 | } 43 | 44 | dataList.add(ByteBuffer.wrap(chunks.get(i).data)); 45 | } 46 | }else{ 47 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, 48 | "Malformed OP_RETURN format. Use 'OP_FALSE OP_RETURN'"); 49 | } 50 | 51 | 52 | }else{ 53 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, 54 | "Invalid Script or malformed Data in Script"); 55 | } 56 | } 57 | 58 | @Override 59 | public Script getLockingScript() { 60 | 61 | ScriptBuilder builder = new ScriptBuilder(); 62 | 63 | builder.op(ScriptOpCodes.OP_FALSE); 64 | builder.op(ScriptOpCodes.OP_RETURN); 65 | 66 | for (ByteBuffer buffer: dataList) { 67 | builder.data(buffer.array()); 68 | } 69 | 70 | return builder.build(); 71 | 72 | } 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/transaction/SigHashTest.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.transaction; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.google.common.base.Charsets; 6 | import org.junit.Test; 7 | import org.twostack.bitcoin4j.Utils; 8 | import org.twostack.bitcoin4j.exception.SigHashException; 9 | import org.twostack.bitcoin4j.script.Script; 10 | 11 | import java.io.IOException; 12 | import java.io.InputStreamReader; 13 | import java.math.BigInteger; 14 | import java.util.Arrays; 15 | 16 | import static org.junit.Assert.assertTrue; 17 | 18 | public class SigHashTest { 19 | 20 | private void runSighashTests(String filename ) throws IOException, SigHashException { 21 | 22 | JsonNode json = new ObjectMapper() 23 | .readTree(new InputStreamReader(getClass().getResourceAsStream(filename), Charsets.UTF_8)); 24 | for (JsonNode test : json) { 25 | if (test.isArray() && test.size() == 1 && test.get(0).isTextual()) 26 | continue; 27 | 28 | String txbuf = test.get(0).asText(); 29 | System.out.println(txbuf); 30 | String scriptbuf = test.get(1).asText(); 31 | Script subscript = Script.fromByteArray(Utils.HEX.decode(scriptbuf)); 32 | int nin = test.get(2).asInt(); 33 | int nhashtype = test.get(3).asInt() >> 0; 34 | String sighashbuf = test.get(4).asText(); 35 | Transaction tx = Transaction.fromHex(txbuf); 36 | 37 | // make sure transaction serialize/deserialize is isomorphic 38 | assertTrue(Arrays.equals(tx.serialize(), Utils.HEX.decode(txbuf))); 39 | 40 | // sighash ought to be correct 41 | SigHash sigHash = new SigHash(); 42 | byte[] hash = sigHash.createHash(tx, nhashtype, nin, subscript, BigInteger.ZERO); 43 | 44 | //Reverse bytes to get them in LE/serialized format 45 | assertTrue(Arrays.equals(Utils.reverseBytes(hash), Utils.HEX.decode(sighashbuf))); 46 | 47 | } 48 | } 49 | 50 | //FIXME: IMPORTANT: Sighash vectors (from bsv javascript library) have been pruned by about 10 tests which generated 51 | // BigInt values on TransactionOutput serializer that were > 8 bytes long, throwing Exception. 52 | // Figure out if this is OK, or if there's a bug with working with BigInteger Max values. 53 | @Test 54 | public void bitcoinCoreSighashTests() throws IOException, SigHashException { 55 | 56 | runSighashTests("sighash.json"); 57 | } 58 | 59 | @Test 60 | public void bitcoinSVSighashTests() throws IOException, SigHashException { 61 | 62 | runSighashTests("sighash-sv.json"); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/script/ScriptPatternTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 John L. Jegutanis 3 | * Copyright 2018 Andreas Schildbach 4 | * Copyright 2019 Tim Strasser 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package org.twostack.bitcoin4j.script; 20 | 21 | import com.google.common.collect.Lists; 22 | import org.junit.Test; 23 | import org.twostack.bitcoin4j.ECKey; 24 | 25 | 26 | import java.util.List; 27 | 28 | import static org.junit.Assert.assertFalse; 29 | import static org.junit.Assert.assertTrue; 30 | import static org.twostack.bitcoin4j.script.ScriptOpCodes.OP_CHECKMULTISIG; 31 | 32 | public class ScriptPatternTest { 33 | private List keys = Lists.newArrayList(new ECKey(), new ECKey(), new ECKey()); 34 | 35 | @Test 36 | public void testCreateP2PKHOutputScript() { 37 | assertTrue(ScriptPattern.isP2PKH( 38 | ScriptBuilder.createP2PKHOutputScript(keys.get(0)) 39 | )); 40 | } 41 | 42 | // @Test 43 | // public void testCreateP2SHOutputScript() { 44 | // assertTrue(ScriptPattern.isP2SH( ScriptBuilder.createP2SHOutputScript(2, keys) )); 45 | // } 46 | 47 | @Test 48 | public void testCreateP2PKOutputScript() { 49 | assertTrue(ScriptPattern.isP2PK( 50 | ScriptBuilder.createP2PKOutputScript(keys.get(0)) 51 | )); 52 | } 53 | 54 | // @Test 55 | // public void testCreateMultiSigOutputScript() { 56 | // assertTrue(ScriptPattern.isSentToMultisig( ScriptBuilder.createMultiSigOutputScript(2, keys) )); 57 | // } 58 | 59 | @Test 60 | public void testIsSentToMultisigFailure() { 61 | // at the time this test was written, the following script would result in throwing 62 | // put a non OP_N opcode first and second-to-last positions 63 | Script evil = new ScriptBuilder() 64 | .op(0xff) 65 | .op(0xff) 66 | .op(0xff) 67 | .op(OP_CHECKMULTISIG) 68 | .build(); 69 | assertFalse(ScriptPattern.isSentToMultisig(evil)); 70 | } 71 | 72 | @Test 73 | public void testCreateOpReturnScript() { 74 | assertTrue(ScriptPattern.isOpReturn( 75 | ScriptBuilder.createOpReturnScript(new byte[10]) 76 | )); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/base58/Base58DecodeCheckedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * Copyright 2014 Andreas Schildbach 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.twostack.bitcoin4j.base58; 19 | 20 | import org.junit.Assume; 21 | import org.junit.Rule; 22 | import org.junit.experimental.theories.DataPoints; 23 | import org.junit.experimental.theories.Theories; 24 | import org.junit.experimental.theories.Theory; 25 | import org.junit.rules.ExpectedException; 26 | import org.junit.runner.RunWith; 27 | import org.twostack.bitcoin4j.address.Base58; 28 | import org.twostack.bitcoin4j.exception.AddressFormatException; 29 | 30 | @RunWith(Theories.class) 31 | public class Base58DecodeCheckedTest { 32 | 33 | @Rule 34 | public ExpectedException expectedException = ExpectedException.none(); 35 | 36 | private static final String BASE58_ALPHABET = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; 37 | private boolean containsOnlyValidBase58Chars(String input) { 38 | for(String s : input.split("")) { 39 | if (!BASE58_ALPHABET.contains(s)) { 40 | return false; 41 | } 42 | } 43 | return true; 44 | } 45 | 46 | @DataPoints 47 | public static String[] parameters = new String[]{ 48 | "4stwEBjT6FYyVV", 49 | "93VYUMzRG9DdbRP72uQXjaWibbQwygnvaCu9DumcqDjGybD864T", 50 | "J0F12TrwUP45BMd", 51 | "4s" 52 | }; 53 | 54 | @Theory 55 | public void testDecodeChecked(String input) { 56 | Assume.assumeTrue(containsOnlyValidBase58Chars(input)); 57 | Assume.assumeTrue(input.length() > 4); 58 | Base58.decodeChecked(input); 59 | } 60 | 61 | @Theory 62 | public void decode_invalidCharacter_notInAlphabet(String input) { 63 | Assume.assumeFalse(containsOnlyValidBase58Chars(input)); 64 | Assume.assumeTrue(input.length() > 4); 65 | expectedException.expect(AddressFormatException.InvalidCharacter.class); 66 | Base58.decodeChecked(input); 67 | } 68 | 69 | @Theory 70 | public void testDecodeChecked_shortInput(String input) { 71 | Assume.assumeTrue(containsOnlyValidBase58Chars(input)); 72 | Assume.assumeTrue(input.length() < 4); 73 | expectedException.expect(AddressFormatException.InvalidDataLength.class); 74 | Base58.decodeChecked(input); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/utils/TestUtil.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.utils; 2 | 3 | import org.twostack.bitcoin4j.UnsafeByteArrayOutputStream; 4 | import org.twostack.bitcoin4j.Utils; 5 | import org.twostack.bitcoin4j.script.Script; 6 | import org.twostack.bitcoin4j.script.ScriptOpCodes; 7 | 8 | import java.io.IOException; 9 | import java.math.BigInteger; 10 | import java.nio.charset.StandardCharsets; 11 | import java.util.EnumSet; 12 | import java.util.Set; 13 | 14 | import static org.twostack.bitcoin4j.Utils.HEX; 15 | import static org.twostack.bitcoin4j.script.ScriptOpCodes.OP_INVALIDOPCODE; 16 | 17 | public class TestUtil { 18 | 19 | 20 | public static Script parseScriptString(String string) throws IOException { 21 | String[] words = string.split("[ \\t\\n]"); 22 | 23 | UnsafeByteArrayOutputStream out = new UnsafeByteArrayOutputStream(); 24 | 25 | for(String w : words) { 26 | if (w.equals("")) 27 | continue; 28 | if (w.matches("^-?[0-9]*$")) { 29 | // Number 30 | long val = Long.parseLong(w); 31 | if (val >= -1 && val <= 16) 32 | out.write(Script.encodeToOpN((int)val)); 33 | else 34 | Script.writeBytes(out, Utils.reverseBytes(Utils.encodeMPI(BigInteger.valueOf(val), false))); 35 | } else if (w.matches("^0x[0-9a-fA-F]*$")) { 36 | // Raw hex data, inserted NOT pushed onto stack: 37 | out.write(HEX.decode(w.substring(2).toLowerCase())); 38 | } else if (w.length() >= 2 && w.startsWith("'") && w.endsWith("'")) { 39 | // Single-quoted string, pushed as data. NOTE: this is poor-man's 40 | // parsing, spaces/tabs/newlines in single-quoted strings won't work. 41 | Script.writeBytes(out, w.substring(1, w.length() - 1).getBytes(StandardCharsets.UTF_8)); 42 | } else if (ScriptOpCodes.getOpCode(w) != OP_INVALIDOPCODE) { 43 | // opcode, e.g. OP_ADD or OP_1: 44 | out.write(ScriptOpCodes.getOpCode(w)); 45 | } else if (w.startsWith("OP_") && ScriptOpCodes.getOpCode(w.substring(3)) != OP_INVALIDOPCODE) { 46 | // opcode, e.g. OP_ADD or OP_1: 47 | out.write(ScriptOpCodes.getOpCode(w.substring(3))); 48 | } else { 49 | throw new RuntimeException("Invalid word: '" + w + "'"); 50 | } 51 | } 52 | 53 | return new Script(out.toByteArray()); 54 | } 55 | 56 | 57 | public static Set parseVerifyFlags(String str) { 58 | Set flags = EnumSet.noneOf(Script.VerifyFlag.class); 59 | if (!"NONE".equals(str)) { 60 | for (String flag : str.split(",")) { 61 | try { 62 | flags.add(Script.VerifyFlag.valueOf(flag)); 63 | } catch (IllegalArgumentException x) { 64 | System.out.println("Cannot handle verify flag {} -- ignored."); 65 | } 66 | } 67 | } 68 | return flags; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/utils/VarIntTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * Copyright 2018 Andreas Schildbach 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.twostack.bitcoin4j.utils; 19 | 20 | import org.junit.Test; 21 | import org.twostack.bitcoin4j.VarInt; 22 | 23 | import static org.junit.Assert.assertEquals; 24 | 25 | public class VarIntTest { 26 | 27 | @Test 28 | public void testBytes() throws Exception { 29 | VarInt a = new VarInt(10); // with widening conversion 30 | assertEquals(1, a.getSizeInBytes()); 31 | assertEquals(1, a.encode().length); 32 | assertEquals(10, new VarInt(a.encode(), 0).intValue()); 33 | } 34 | 35 | @Test 36 | public void testShorts() throws Exception { 37 | VarInt a = new VarInt(64000); // with widening conversion 38 | assertEquals(3, a.getSizeInBytes()); 39 | assertEquals(3, a.encode().length); 40 | assertEquals(64000, new VarInt(a.encode(), 0).intValue()); 41 | } 42 | 43 | @Test 44 | public void testShortFFFF() throws Exception { 45 | VarInt a = new VarInt(0xFFFFL); 46 | assertEquals(3, a.getSizeInBytes()); 47 | assertEquals(3, a.encode().length); 48 | assertEquals(0xFFFFL, new VarInt(a.encode(), 0).intValue()); 49 | } 50 | 51 | @Test 52 | public void testInts() throws Exception { 53 | VarInt a = new VarInt(0xAABBCCDDL); 54 | assertEquals(5, a.getSizeInBytes()); 55 | assertEquals(5, a.encode().length); 56 | byte[] bytes = a.encode(); 57 | assertEquals(0xAABBCCDDL, new VarInt(bytes, 0).longValue()); 58 | } 59 | 60 | @Test 61 | public void testIntFFFFFFFF() throws Exception { 62 | VarInt a = new VarInt(0xFFFFFFFFL); 63 | assertEquals(5, a.getSizeInBytes()); 64 | assertEquals(5, a.encode().length); 65 | byte[] bytes = a.encode(); 66 | assertEquals(0xFFFFFFFFL, new VarInt(bytes, 0).longValue()); 67 | } 68 | 69 | @Test 70 | public void testLong() throws Exception { 71 | VarInt a = new VarInt(0xCAFEBABEDEADBEEFL); 72 | assertEquals(9, a.getSizeInBytes()); 73 | assertEquals(9, a.encode().length); 74 | byte[] bytes = a.encode(); 75 | assertEquals(0xCAFEBABEDEADBEEFL, new VarInt(bytes, 0).longValue()); 76 | } 77 | 78 | @Test 79 | public void testSizeOfNegativeInt() throws Exception { 80 | // shouldn't normally be passed, but at least stay consistent (bug regression test) 81 | assertEquals(VarInt.sizeOf(-1), new VarInt(-1).encode().length); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/TransactionOutpoint.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2021 Stephan M. February 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.twostack.bitcoin4j.transaction; 19 | 20 | import org.twostack.bitcoin4j.script.Script; 21 | 22 | import java.math.BigInteger; 23 | import java.util.Objects; 24 | 25 | /** 26 | * This is more traditionally referred to as a UTXO. The Transaction Outpoint is a convenience 27 | * POJO that ties together information from the Transaction Output we are spending from . 28 | * 29 | * A TransactionOutput datastructure by itself does not contain all this information. 30 | * 31 | */ 32 | public class TransactionOutpoint { 33 | 34 | private String transactionId; 35 | private Integer outputIndex; 36 | private BigInteger satoshis; 37 | private Script lockingScript; 38 | 39 | public String getTransactionId() { 40 | return transactionId; 41 | } 42 | 43 | public void setTransactionId(String transactionId) { 44 | this.transactionId = transactionId; 45 | } 46 | 47 | public Integer getOutputIndex() { 48 | return outputIndex; 49 | } 50 | 51 | public void setOutputIndex(Integer outputIndex) { 52 | this.outputIndex = outputIndex; 53 | } 54 | 55 | public BigInteger getSatoshis() { 56 | return satoshis; 57 | } 58 | 59 | public void setSatoshis(BigInteger satoshis) { 60 | this.satoshis = satoshis; 61 | } 62 | 63 | public Script getLockingScript() { 64 | return lockingScript; 65 | } 66 | 67 | public void setLockingScript(Script lockingScript) { 68 | this.lockingScript = lockingScript; 69 | } 70 | 71 | TransactionOutpoint(String transactionId, Integer outputIndex, BigInteger satoshis, Script lockingScript){ 72 | this.transactionId = transactionId; 73 | this.outputIndex = outputIndex; 74 | this.satoshis = satoshis; 75 | this.lockingScript = lockingScript; 76 | } 77 | TransactionOutpoint(){ } 78 | 79 | @Override 80 | public boolean equals(Object o) { 81 | if (this == o) return true; 82 | if (o == null || getClass() != o.getClass()) return false; 83 | TransactionOutpoint outpoint = (TransactionOutpoint) o; 84 | return transactionId.equals(outpoint.transactionId) && outputIndex.equals(outpoint.outputIndex) && satoshis.equals(outpoint.satoshis) && Objects.equals(lockingScript, outpoint.lockingScript); 85 | } 86 | 87 | @Override 88 | public int hashCode() { 89 | return Objects.hash(transactionId, outputIndex, satoshis, lockingScript); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/P2PKHUnlockBuilder.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2021 Stephan M. February 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.twostack.bitcoin4j.transaction; 18 | 19 | import org.twostack.bitcoin4j.PublicKey; 20 | import org.twostack.bitcoin4j.Utils; 21 | import org.twostack.bitcoin4j.exception.SignatureDecodeException; 22 | import org.twostack.bitcoin4j.script.*; 23 | 24 | import java.util.List; 25 | 26 | public class P2PKHUnlockBuilder extends UnlockingScriptBuilder { 27 | 28 | 29 | private PublicKey signerPubkey; 30 | 31 | public P2PKHUnlockBuilder(Script script) throws SignatureDecodeException { 32 | parse(script); 33 | } 34 | 35 | public P2PKHUnlockBuilder(PublicKey publicKey) { 36 | this.signerPubkey = publicKey; 37 | } 38 | 39 | private void parse(Script script) throws SignatureDecodeException { 40 | 41 | if (script != null) { 42 | 43 | List chunkList = script.getChunks(); 44 | 45 | if (chunkList.size() != 2){ 46 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Wrong number of data elements for P2PKH ScriptSig"); 47 | } 48 | 49 | byte[] sig = chunkList.get(0).data; 50 | byte[] pubKey = chunkList.get(1).data; 51 | 52 | signerPubkey = PublicKey.fromHex(Utils.HEX.encode(pubKey)); 53 | signatures.add(TransactionSignature.fromTxFormat(Utils.HEX.encode(sig))); 54 | 55 | }else{ 56 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Invalid Script or Malformed Script."); 57 | } 58 | } 59 | 60 | @Override 61 | public Script getUnlockingScript() { 62 | 63 | List signatures = getSignatures(); 64 | 65 | TransactionSignature signature = null; 66 | if (!signatures.isEmpty()) { 67 | signature = getSignatures().get(0); 68 | } 69 | 70 | if (signature == null || signerPubkey == null){ 71 | return new ScriptBuilder().build(); //return empty script; otherwise we will barf on early serialize (prior to signing) 72 | } 73 | 74 | try { 75 | 76 | return new ScriptBuilder().data(signature.toTxFormat()).data(signerPubkey.getPubKeyBytes()).build(); 77 | }catch(Exception ex){ 78 | System.out.println(ex.getMessage()); 79 | ex.printStackTrace(); //FIXME: Handle more gracefully 80 | return new ScriptBuilder().build(); 81 | } 82 | } 83 | 84 | 85 | public PublicKey getSignerPubkey() { 86 | return signerPubkey; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/utils/BriefLogFormatter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.utils; 18 | 19 | import java.io.PrintWriter; 20 | import java.io.StringWriter; 21 | import java.io.Writer; 22 | import java.text.MessageFormat; 23 | import java.util.Date; 24 | import java.util.logging.*; 25 | 26 | /** 27 | * A Java logging formatter that writes more compact output than the default. 28 | */ 29 | public class BriefLogFormatter extends Formatter { 30 | private static final MessageFormat messageFormat = new MessageFormat("{3,date,HH:mm:ss} {0} {1}.{2}: {4}\n{5}"); 31 | 32 | // OpenJDK made a questionable, backwards incompatible change to the Logger implementation. It internally uses 33 | // weak references now which means simply fetching the logger and changing its configuration won't work. We must 34 | // keep a reference to our custom logger around. 35 | private static final Logger logger = Logger.getLogger(""); 36 | 37 | /** Configures JDK logging to use this class for everything. */ 38 | public static void init() { 39 | final Handler[] handlers = logger.getHandlers(); 40 | // In regular Java there is always a handler. Avian doesn't install one however. 41 | if (handlers.length > 0) 42 | handlers[0].setFormatter(new BriefLogFormatter()); 43 | } 44 | 45 | public static void initVerbose() { 46 | init(); 47 | logger.setLevel(Level.ALL); 48 | logger.log(Level.FINE, "test"); 49 | } 50 | 51 | public static void initWithSilentBitcoinJ() { 52 | init(); 53 | Logger.getLogger("org.bitcoinj").setLevel(Level.SEVERE); 54 | } 55 | 56 | @Override 57 | public String format(LogRecord logRecord) { 58 | Object[] arguments = new Object[6]; 59 | arguments[0] = logRecord.getThreadID(); 60 | String fullClassName = logRecord.getSourceClassName(); 61 | int lastDot = fullClassName.lastIndexOf('.'); 62 | String className = fullClassName.substring(lastDot + 1); 63 | arguments[1] = className; 64 | arguments[2] = logRecord.getSourceMethodName(); 65 | arguments[3] = new Date(logRecord.getMillis()); 66 | arguments[4] = logRecord.getMessage(); 67 | if (logRecord.getThrown() != null) { 68 | Writer result = new StringWriter(); 69 | logRecord.getThrown().printStackTrace(new PrintWriter(result)); 70 | arguments[5] = result.toString(); 71 | } else { 72 | arguments[5] = ""; 73 | } 74 | return messageFormat.format(arguments); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/crypto/DRMWorkaround.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright by the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.crypto; 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | import org.twostack.bitcoin4j.Utils; 22 | 23 | import java.lang.reflect.Constructor; 24 | import java.lang.reflect.Field; 25 | import java.lang.reflect.Method; 26 | import java.lang.reflect.Modifier; 27 | 28 | public class DRMWorkaround { 29 | private static final Logger log = LoggerFactory.getLogger(DRMWorkaround.class); 30 | 31 | private static boolean done = false; 32 | 33 | public static void maybeDisableExportControls() { 34 | // This sorry story is documented in https://bugs.openjdk.java.net/browse/JDK-7024850 35 | // Oracle received permission to ship AES-256 by default in 2011, but didn't get around to it for Java 8 36 | // even though that shipped in 2014! That's dumb. So we disable the ridiculous US government mandated DRM 37 | // for AES-256 here, as Tor/BIP38 requires it. 38 | 39 | if (done) return; 40 | done = true; 41 | 42 | if (Utils.isAndroidRuntime() || Utils.isOpenJDKRuntime()) 43 | return; 44 | try { 45 | Field gate = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted"); 46 | gate.setAccessible(true); 47 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 48 | modifiersField.setAccessible(true); 49 | modifiersField.setInt(gate, gate.getModifiers() & ~Modifier.FINAL); 50 | gate.setBoolean(null, false); 51 | final Field allPerm = Class.forName("javax.crypto.CryptoAllPermission").getDeclaredField("INSTANCE"); 52 | allPerm.setAccessible(true); 53 | Object accessAllAreasCard = allPerm.get(null); 54 | final Constructor constructor = Class.forName("javax.crypto.CryptoPermissions").getDeclaredConstructor(); 55 | constructor.setAccessible(true); 56 | Object coll = constructor.newInstance(); 57 | Method addPerm = Class.forName("javax.crypto.CryptoPermissions").getDeclaredMethod("add", java.security.Permission.class); 58 | addPerm.setAccessible(true); 59 | addPerm.invoke(coll, accessAllAreasCard); 60 | Field defaultPolicy = Class.forName("javax.crypto.JceSecurity").getDeclaredField("defaultPolicy"); 61 | defaultPolicy.setAccessible(true); 62 | defaultPolicy.set(null, coll); 63 | } catch (Exception e) { 64 | log.warn("Failed to deactivate AES-256 barrier logic, Tor mode/BIP38 decryption may crash if this JVM requires it: " + e.getMessage()); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/transaction/tx_creation.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "from": [ 4 | [ 5 | { 6 | "address": "mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1", 7 | "txId": "a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458", 8 | "outputIndex": 0, 9 | "scriptPubKey": "76a91488d9931ea73d60eaf7e5671efc0552b912911f2a88ac", 10 | "satoshis": 1020000 11 | }, 12 | [], 13 | 0 14 | ] 15 | ], 16 | "to": [ 17 | [ 18 | "mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc", 19 | 1010000 20 | ] 21 | ], 22 | "sign": [ 23 | "cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY", 24 | 1 25 | ], 26 | "serialize": "01000000015884e5db9de218238671572340b207ee85b628074e7e467096c267266baf77a4000000006b4830450221009972100061da4a17a471ac1906c18bb5445c03da2a0be52c59aca6c58f1e342302202b7a19a22572cabb6e55c368ebdb5921541358fa969d5c76b5e0d6ad3f26a7d701210223078d2942df62c45621d209fab84ea9a7a23346201b7727b9b45a29c4e76f5effffffff0150690f00000000001976a9147821c0a3768aa9d1a37e16cf76002aef5373f1a888ac00000000" 27 | }, 28 | { 29 | "from": [ 30 | [ 31 | { 32 | "txId": "e42447187db5a29d6db161661e4bc66d61c3e499690fe5ea47f87b79ca573986", 33 | "outputIndex": 1, 34 | "address": "mgBCJAsvzgT2qNNeXsoECg2uPKrUsZ76up", 35 | "scriptPubKey": "76a914073b7eae2823efa349e3b9155b8a735526463a0f88ac", 36 | "satoshis": 1080000 37 | }, 38 | [], 39 | 0 40 | ] 41 | ], 42 | "to": [ 43 | [ 44 | "mn9new5vPYWuVN5m3gUBujfKh1uPQvR9mf", 45 | 500000 46 | ], 47 | [ 48 | "mw5ctwgEaNRbxkM4JhXH3rp5AyGvTWDZCD", 49 | 570000 50 | ] 51 | ], 52 | "sign": [ 53 | "cSQUuwwJBAg6tYQhzqqLWW115D1s5KFZDyhCF2ffrnukZxMK6rNZ", 54 | 1 55 | ], 56 | "serialize": "0100000001863957ca797bf847eae50f6999e4c3616dc64b1e6661b16d9da2b57d184724e4010000006b483045022100855691c90510edf83ab632f0a0b17f5202d2cf7071050dcf0c2778325ed403cd022014ee7a4e787da8bc088d2ece43108a7b8d7112eba89876a27bb44195a0715a910121039dd446bbc85db6917f39c0b4c295b0f8cce76d1926fa76d7b84e3f7ff1c5eec5ffffffff0220a10700000000001976a91448c819246ae5645ceecd41fbe1aa6202a0a9b5ca88ac90b20800000000001976a914aab76ba4877d696590d94ea3e02948b55294815188ac00000000" 57 | }, 58 | { 59 | "from": [[ 60 | { 61 | "address": "mgJT8iegL4f9NCgQFeFyfvnSw1Yj4M5Woi", 62 | "txId": "f50e13cecda9a438ebd7df213a2899e42b2461a18d4630ee773d26b4f2688bdc", 63 | "outputIndex": 1, 64 | "scriptPubKey": "76a914089acaba6af8b2b4fb4bed3b747ab1e4e60b496588ac", 65 | "satoshis": 1000000 66 | }, 67 | [], 68 | 0 69 | ]], 70 | "to": [ 71 | [ 72 | "n3riXZowrjGnY74rx7Hdi9wCyvgyJC28zZ", 73 | 990000 74 | ] 75 | ], 76 | "sign": [ 77 | "cPwWtDztEgRCMCU8pMQp4HgphvyadrAsYBrCjXUZuDSmnZkyoyNF", 78 | 1 79 | ], 80 | "serialize": "0100000001dc8b68f2b4263d77ee30468da161242be499283a21dfd7eb38a4a9cdce130ef5010000006a473044022012610834051e6af8594dd5d9c47123d6ce03537d321f9fe3f6ff244b23f47dd5022034901bb0d83688758a9248fdef48bd2000b55cf70111cbef8f206e72a31aaf61012103e26b47e7c0d8946954bf9dd4bc7f9e415437eb98271d05f69e78cef8fc6c9a54ffffffff01301b0f00000000001976a914f50f9826ef186074c6fe206cca6b71472ff07ba888ac00000000" 81 | } 82 | ] 83 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/exception/VerificationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.exception; 18 | 19 | @SuppressWarnings("serial") 20 | public class VerificationException extends RuntimeException { 21 | public VerificationException(String msg) { 22 | super(msg); 23 | } 24 | 25 | public VerificationException(Exception e) { 26 | super(e); 27 | } 28 | 29 | public VerificationException(String msg, Throwable t) { 30 | super(msg, t); 31 | } 32 | 33 | public static class EmptyInputsOrOutputs extends VerificationException { 34 | public EmptyInputsOrOutputs() { 35 | super("Transaction had no inputs or no outputs."); 36 | } 37 | } 38 | 39 | public static class LargerThanMaxBlockSize extends VerificationException { 40 | public LargerThanMaxBlockSize() { 41 | super("Transaction larger than MAX_BLOCK_SIZE"); 42 | } 43 | } 44 | 45 | public static class DuplicatedOutPoint extends VerificationException { 46 | public DuplicatedOutPoint() { 47 | super("Duplicated outpoint"); 48 | } 49 | } 50 | 51 | public static class NegativeValueOutput extends VerificationException { 52 | public NegativeValueOutput() { 53 | super("Transaction output negative"); 54 | } 55 | } 56 | 57 | public static class ExcessiveValue extends VerificationException { 58 | public ExcessiveValue() { 59 | super("Total transaction output value greater than possible"); 60 | } 61 | } 62 | 63 | 64 | public static class CoinbaseScriptSizeOutOfRange extends VerificationException { 65 | public CoinbaseScriptSizeOutOfRange() { 66 | super("Coinbase script size out of range"); 67 | } 68 | } 69 | 70 | 71 | public static class BlockVersionOutOfDate extends VerificationException { 72 | public BlockVersionOutOfDate(final long version) { 73 | super("Block version #" 74 | + version + " is outdated."); 75 | } 76 | } 77 | 78 | public static class UnexpectedCoinbaseInput extends VerificationException { 79 | public UnexpectedCoinbaseInput() { 80 | super("Coinbase input as input in non-coinbase transaction"); 81 | } 82 | } 83 | 84 | public static class CoinbaseHeightMismatch extends VerificationException { 85 | public CoinbaseHeightMismatch(final String message) { 86 | super(message); 87 | } 88 | } 89 | 90 | public static class NoncanonicalSignature extends VerificationException { 91 | public NoncanonicalSignature() { 92 | super("Signature encoding is not canonical"); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/crypto/MnemonicCodeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Ken Sedgwick 3 | * Copyright 2014 Andreas Schildbach 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.twostack.bitcoin4j.crypto; 19 | 20 | import org.junit.Before; 21 | import org.junit.Test; 22 | import org.twostack.bitcoin4j.Utils; 23 | import org.twostack.bitcoin4j.exception.MnemonicException; 24 | 25 | import java.io.IOException; 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | 29 | import static org.twostack.bitcoin4j.Utils.WHITESPACE_SPLITTER; 30 | 31 | /** 32 | * Test the various guard clauses of {@link MnemonicCode}. 33 | * 34 | * See {@link MnemonicCodeVectorsTest} test vectors. 35 | */ 36 | public class MnemonicCodeTest { 37 | 38 | private MnemonicCode mc; 39 | 40 | @Before 41 | public void setup() throws IOException { 42 | mc = new MnemonicCode(); 43 | } 44 | 45 | @Test(expected = MnemonicException.MnemonicLengthException.class) 46 | public void testBadEntropyLength() throws Exception { 47 | byte[] entropy = Utils.HEX.decode("7f7f7f7f7f7f7f7f7f7f7f7f7f7f"); 48 | mc.toMnemonic(entropy); 49 | } 50 | 51 | @Test(expected = MnemonicException.MnemonicLengthException.class) 52 | public void testBadLength() throws Exception { 53 | List words = WHITESPACE_SPLITTER.splitToList("risk tiger venture dinner age assume float denial penalty hello"); 54 | mc.check(words); 55 | } 56 | 57 | @Test(expected = MnemonicException.MnemonicWordException.class) 58 | public void testBadWord() throws Exception { 59 | List words = WHITESPACE_SPLITTER.splitToList("risk tiger venture dinner xyzzy assume float denial penalty hello game wing"); 60 | mc.check(words); 61 | } 62 | 63 | @Test(expected = MnemonicException.MnemonicChecksumException.class) 64 | public void testBadChecksum() throws Exception { 65 | List words = WHITESPACE_SPLITTER.splitToList("bless cloud wheel regular tiny venue bird web grief security dignity zoo"); 66 | mc.check(words); 67 | } 68 | 69 | @Test(expected = MnemonicException.MnemonicLengthException.class) 70 | public void testEmptyMnemonic() throws Exception { 71 | List words = new ArrayList<>(); 72 | mc.check(words); 73 | } 74 | 75 | @Test(expected = MnemonicException.MnemonicLengthException.class) 76 | public void testEmptyEntropy() throws Exception { 77 | byte[] entropy = {}; 78 | mc.toMnemonic(entropy); 79 | } 80 | 81 | @Test(expected = NullPointerException.class) 82 | public void testNullPassphrase() throws Exception { 83 | List code = WHITESPACE_SPLITTER.splitToList("legal winner thank year wave sausage worth useful legal winner thank yellow"); 84 | MnemonicCode.toSeed(code, null); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto init 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto init 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :init 68 | @rem Get command-line arguments, handling Windows variants 69 | 70 | if not "%OS%" == "Windows_NT" goto win9xME_args 71 | 72 | :win9xME_args 73 | @rem Slurp the command line arguments. 74 | set CMD_LINE_ARGS= 75 | set _SKIP=2 76 | 77 | :win9xME_args_slurp 78 | if "x%~1" == "x" goto execute 79 | 80 | set CMD_LINE_ARGS=%* 81 | 82 | :execute 83 | @rem Setup the command line 84 | 85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 86 | 87 | 88 | @rem Execute Gradle 89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 90 | 91 | :end 92 | @rem End local scope for the variables with windows NT shell 93 | if "%ERRORLEVEL%"=="0" goto mainEnd 94 | 95 | :fail 96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 97 | rem the _cmd.exe /c_ return code! 98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 99 | exit /b 1 100 | 101 | :mainEnd 102 | if "%OS%"=="Windows_NT" endlocal 103 | 104 | :omega 105 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/crypto/HDUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Matija Mazi. 3 | * Copyright 2014 Giannis Dzegoutanis. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.twostack.bitcoin4j.crypto; 19 | 20 | import org.bouncycastle.crypto.digests.SHA512Digest; 21 | import org.bouncycastle.crypto.macs.HMac; 22 | import org.bouncycastle.crypto.params.KeyParameter; 23 | import org.twostack.bitcoin4j.ECKey; 24 | 25 | import javax.annotation.Nonnull; 26 | import java.nio.ByteBuffer; 27 | import java.util.Arrays; 28 | import java.util.List; 29 | 30 | /** 31 | * Static utilities used in BIP 32 Hierarchical Deterministic Wallets (HDW). 32 | */ 33 | public final class HDUtils { 34 | 35 | static HMac createHmacSha512Digest(byte[] key) { 36 | SHA512Digest digest = new SHA512Digest(); 37 | HMac hMac = new HMac(digest); 38 | hMac.init(new KeyParameter(key)); 39 | return hMac; 40 | } 41 | 42 | static byte[] hmacSha512(HMac hmacSha512, byte[] input) { 43 | hmacSha512.reset(); 44 | hmacSha512.update(input, 0, input.length); 45 | byte[] out = new byte[64]; 46 | hmacSha512.doFinal(out, 0); 47 | return out; 48 | } 49 | 50 | public static byte[] hmacSha512(byte[] key, byte[] data) { 51 | return hmacSha512(createHmacSha512Digest(key), data); 52 | } 53 | 54 | static byte[] toCompressed(byte[] uncompressedPoint) { 55 | return ECKey.CURVE.getCurve().decodePoint(uncompressedPoint).getEncoded(true); 56 | } 57 | 58 | static byte[] longTo4ByteArray(long n) { 59 | byte[] bytes = Arrays.copyOfRange(ByteBuffer.allocate(8).putLong(n).array(), 4, 8); 60 | assert bytes.length == 4 : bytes.length; 61 | return bytes; 62 | } 63 | 64 | /** 65 | * Append a derivation level to an existing path 66 | * 67 | * @deprecated Use {@code HDPath#extend} 68 | */ 69 | @Deprecated 70 | public static HDPath append(List path, ChildNumber childNumber) { 71 | return new HDPath(path).extend(childNumber); 72 | } 73 | 74 | /** 75 | * Concatenate two derivation paths 76 | * 77 | * @deprecated Use {@code HDPath#extend} 78 | */ 79 | @Deprecated 80 | public static HDPath concat(List path, List path2) { 81 | return new HDPath(path).extend(path2); 82 | } 83 | 84 | /** 85 | * Convert to a string path, starting with "M/" 86 | * 87 | * @deprecated Use {@code HDPath#toString} 88 | */ 89 | @Deprecated 90 | public static String formatPath(List path) { 91 | return HDPath.M(path).toString(); 92 | } 93 | 94 | /** 95 | * Create an HDPath from a path string. 96 | * 97 | * @deprecated Use {@code HDPath.parsePath} 98 | */ 99 | @Deprecated 100 | public static HDPath parsePath(@Nonnull String path) { 101 | return HDPath.parsePath(path); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/P2PKHLockBuilder.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2021 Stephan M. February 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.twostack.bitcoin4j.transaction; 18 | 19 | import org.twostack.bitcoin4j.PublicKey; 20 | import org.twostack.bitcoin4j.Address; 21 | import org.twostack.bitcoin4j.params.NetworkAddressType; 22 | import org.twostack.bitcoin4j.script.*; 23 | 24 | import java.util.List; 25 | 26 | import static org.twostack.bitcoin4j.script.ScriptOpCodes.*; 27 | 28 | public class P2PKHLockBuilder extends LockingScriptBuilder{ 29 | 30 | 31 | private Address address; 32 | private byte[] pubkeyHash; 33 | 34 | static P2PKHLockBuilder fromPublicKey(PublicKey key, NetworkAddressType networkType){ 35 | Address address = Address.fromKey(networkType, key); 36 | return new P2PKHLockBuilder(address); 37 | } 38 | 39 | public P2PKHLockBuilder(Address address){ 40 | this.address = address; 41 | 42 | if (address != null) { 43 | this.pubkeyHash = address.getHash(); //hash160(pubkey) aka pubkeyHash 44 | } 45 | } 46 | 47 | public P2PKHLockBuilder(Script script){ 48 | parse(script); 49 | } 50 | 51 | private void parse(Script script){ 52 | 53 | if (script != null) { 54 | 55 | List chunkList = script.getChunks(); 56 | 57 | if (chunkList.size() != 5){ 58 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR,"Wrong number of data elements for P2PKH ScriptPubkey"); 59 | } 60 | 61 | if(!( chunkList.get(0).opcode == ScriptOpCodes.OP_DUP && 62 | chunkList.get(1).opcode == ScriptOpCodes.OP_HASH160 && 63 | chunkList.get(3).opcode == ScriptOpCodes.OP_EQUALVERIFY && 64 | chunkList.get(4).opcode == ScriptOpCodes.OP_CHECKSIG )){ 65 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Malformed P2PKH ScriptPubkey script. Mismatched OP_CODES."); 66 | } 67 | 68 | this.pubkeyHash = chunkList.get(2).data; 69 | 70 | }else{ 71 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Invalid Script or Malformed Script."); 72 | } 73 | } 74 | 75 | @Override 76 | public Script getLockingScript() { 77 | 78 | if (this.pubkeyHash == null) { 79 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Missing pubkeyHash. Can't construct the script."); 80 | } 81 | 82 | ScriptBuilder builder = new ScriptBuilder(); 83 | builder.op(OP_DUP); 84 | builder.op(OP_HASH160); 85 | builder.data(this.pubkeyHash); 86 | builder.op(OP_EQUALVERIFY); 87 | builder.op(OP_CHECKSIG); 88 | 89 | return builder.build(); 90 | 91 | } 92 | 93 | public Address getAddress() { 94 | return address; 95 | } 96 | 97 | public byte[] getPubkeyHash() { 98 | return pubkeyHash; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/P2MSLockBuilder.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.transaction; 2 | 3 | import org.twostack.bitcoin4j.PublicKey; 4 | import org.twostack.bitcoin4j.script.*; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.List; 9 | 10 | public class P2MSLockBuilder extends LockingScriptBuilder{ 11 | 12 | List publicKeyList = new ArrayList<>(); 13 | int requiredSigs = 0; 14 | boolean sorting = false; 15 | 16 | 17 | public P2MSLockBuilder(List publicKeys, int requiredSigs){ 18 | 19 | super(); 20 | this.sorting = true; //default to true for sorting when not specified 21 | this.requiredSigs = requiredSigs; 22 | this.publicKeyList = publicKeys; 23 | 24 | } 25 | 26 | public P2MSLockBuilder(List publicKeys, int requiredSigs, boolean sortKeys){ 27 | 28 | super(); 29 | this.sorting = sortKeys; 30 | this.requiredSigs = requiredSigs; 31 | this.publicKeyList = new ArrayList(publicKeys); 32 | 33 | } 34 | 35 | public P2MSLockBuilder(Script script){ 36 | parse(script); 37 | } 38 | 39 | private void parse(Script script){ 40 | 41 | if (script.getChunks().size() > 0){ 42 | 43 | List chunks = script.getChunks(); 44 | 45 | if (chunks.get(chunks.size() - 1).opcode != ScriptOpCodes.OP_CHECKMULTISIG){ 46 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, 47 | "Malformed multisig script. OP_CHECKMULTISIG is missing"); 48 | } 49 | 50 | int keyCount = chunks.get(chunks.size() - 2).opcode - 80; 51 | 52 | publicKeyList = new ArrayList<>(); 53 | 54 | for (int i = 0; i publicKeyList.size()){ 73 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "You can't have more signatures than public keys"); 74 | } 75 | 76 | if (sorting){ 77 | publicKeyList.sort((a, b) -> a.getPubKeyHex().compareTo(b.getPubKeyHex())); 78 | } 79 | 80 | ScriptBuilder builder = new ScriptBuilder(); 81 | 82 | int numRequiredSigsCode = ScriptOpCodes.getOpCode(Integer.toString(requiredSigs)); //e.g. OP_3 means 3 / y 83 | 84 | builder.op(numRequiredSigsCode); 85 | 86 | for (PublicKey pubKey : publicKeyList) { 87 | builder.data(pubKey.getPubKeyBytes()); 88 | } 89 | int pubkeyCountOpCode = ScriptOpCodes.getOpCode(Integer.toString(publicKeyList.size())); //e.g. OP_5 means x / 5 multisig 90 | 91 | builder.op(pubkeyCountOpCode); 92 | builder.op(ScriptOpCodes.OP_CHECKMULTISIG); 93 | 94 | return builder.build(); 95 | 96 | } 97 | 98 | public List getPublicKeys() { 99 | return new ArrayList<>(publicKeyList); 100 | } 101 | 102 | public int getRequiredSigs() { 103 | return requiredSigs; 104 | } 105 | 106 | public boolean isSorting() { 107 | return sorting; 108 | } 109 | 110 | 111 | } 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | ![Java CI](https://github.com/twostack/bitcoin4j/workflows/Java%20CI%20with%20Gradle/badge.svg) 3 | 4 | ## Overview 5 | 6 | Bitcoin4J is a Bitcoin library for the Java Language licensed under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt). 7 | 8 | This library has been built in line with the ideals espoused by [BitcoinSV](https://bitcoinsv.io), 9 | i.e. massive on-chain scaling, protocol stability and original-bitcoin-protocol implementation. 10 | 11 | ### Learn More about BitcoinSV 12 | You can learn more about BitcoinSV by visiting : 13 | * [TwoStack Bitcoin Developer Guide](https://www.twostack.org/docs/getting-started/) 14 | * [TwoStack Youtube Channel](https://youtube.com/twostack) 15 | * [Bitcoin Association Website](https://bitcoinsv.io) 16 | * [BitcoinSV Wiki](https://wiki.bitcoinsv.io/). 17 | 18 | ## Installation 19 | Binaries for the library are [available on Maven Central](https://search.maven.org/artifact/org.twostack/bitcoin4j/1.6.6/jar). 20 | 21 | 22 | ### Gradle Dependencies 23 | ```gradle 24 | implementation("org.twostack:bitcoin4j:1.6.6") 25 | ``` 26 | 27 | ### Maven Dependencies 28 | ```xml 29 | 30 | org.twostack 31 | bitcoin4j 32 | 1.6.6 33 | 34 | ``` 35 | 36 | ## Clean Transaction Builder 37 | Several helper classes and APIs exist to make constructing Transactions more intuitive. 38 | 39 | [See the full example source code](https://github.com/twostack/data-transaction/blob/main/src/main/kotlin/main.kt) 40 | 41 | As a native Java implementation, the library integrates well with other JVM languages, e.g. Kotlin. 42 | ```kotlin 43 | val txBuilder: TransactionBuilder = TransactionBuilder() 44 | val spendingTx: Transaction = txBuilder.spendFromTransaction(aliceFundingTx, 1, Transaction.NLOCKTIME_MAX_VALUE, unlockBuilder) 45 | .spendTo(bobLockingBuilder, BigInteger.valueOf(10000)) 46 | .sendChangeTo(aliceAddress, aliceLockingBuilder) 47 | .withFeePerKb(512) 48 | .build(true) 49 | ``` 50 | 51 | ## Features 52 | 53 | * Unbounded Transaction Types (creating non-standard transactions) 54 | * HD Key Derivation \(BIP32\) 55 | * Mnemonic Seed Support \(BIP39\) 56 | * Original Bitcoin Address format 57 | * A built-in Bitcoin Script Interpreter 58 | * Custom-Script Builder Interface to support novel locking/spending conditions within Script 59 | * P2PKH Transaction Builder - Pay to Pubkey Hash standard Transactions 60 | * P2MS Transaction Builder - Pay to Multisig. This is naked MultiSig (the proper way to do multisig). 61 | * P2PK Transaction Builder - Pay to Public Key standard Transactions 62 | * P2SH Transaction Builder - Pay to Script Hash. This should be considered deprecated. BitcoinSV Nodes support this for backwards compatibility only. 63 | * P2PKHDataLockBuilder - This is something new. Create a spendable data output. Spendable using P2PKH Transaction. 64 | * UnspendableDataLockBuilder - OP_RETURN-style Data builder. Prepends a Transaction Output Script with OP_FALSE OP_RETURN followed by a series of data pushes. 65 | 66 | ### Deprecated Features 67 | The following features represent forks away from the original Bitcoin Protocol. 68 | 69 | This library lacks, and does not implement : 70 | 71 | * Segregated Witness \(Segwit\) Transaction support (Bitcoin Core - BTC) 72 | * Schnorr Transaction Signature support (Bitcoin Cash - BCH) 73 | * Check Datasig \(OP\_CHECKDATASIG\) (Bitcoin Cash - BCH) 74 | * Taproot (Bitcoin Core - BTC) 75 | 76 | ## Acknowledgement 77 | 78 | This library is a fork of the BitcoinJ and BitcoinJ-Cash projects. Contributor acknowledgements have been preserved in the AUTHORS file. 79 | 80 | ## Contact 81 | 82 | You can reach the author at : stephan@twostack.org 83 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/TransactionOutput.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2021 Stephan M. February 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.twostack.bitcoin4j.transaction; 18 | 19 | import org.twostack.bitcoin4j.Utils; 20 | import org.twostack.bitcoin4j.VarInt; 21 | import org.twostack.bitcoin4j.script.Script; 22 | import org.twostack.bitcoin4j.script.ScriptBuilder; 23 | 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | import java.math.BigInteger; 27 | 28 | public class TransactionOutput { 29 | 30 | private BigInteger satoshis = BigInteger.ZERO; 31 | 32 | private LockingScriptBuilder _lockingScriptBuilder; 33 | 34 | public static TransactionOutput fromReader(ReadUtils reader) { 35 | 36 | BigInteger satoshis = reader.readUint64(); 37 | int size = reader.readVarInt().intValue(); 38 | Script script; 39 | if (size != 0) { 40 | script = Script.fromByteArray(reader.readBytes(size)); 41 | } else { 42 | script = new ScriptBuilder().build(); 43 | } 44 | 45 | return new TransactionOutput(satoshis, script); 46 | } 47 | 48 | public TransactionOutput(BigInteger satoshis, LockingScriptBuilder builder){ 49 | this.satoshis = satoshis; 50 | this._lockingScriptBuilder = builder; 51 | } 52 | 53 | public TransactionOutput(BigInteger satoshis, Script script){ 54 | this.satoshis = satoshis; 55 | this._lockingScriptBuilder = new DefaultLockBuilder(script); 56 | } 57 | 58 | public static TransactionOutput fromByteBuffer(byte[] buffer) { 59 | 60 | ReadUtils reader = new ReadUtils(buffer); 61 | 62 | return fromReader(reader); 63 | 64 | } 65 | 66 | public static TransactionOutput fromStream(InputStream is) throws IOException { 67 | 68 | BigInteger satoshis = BigInteger.valueOf(Utils.readInt64FromStream(is)); 69 | int size = VarInt.fromStream(is).intValue(); 70 | Script script; 71 | if (size != 0) { 72 | script = Script.fromByteArray(is.readNBytes(size)); 73 | } else { 74 | script = new ScriptBuilder().build(); 75 | } 76 | 77 | return new TransactionOutput(satoshis, script); 78 | } 79 | 80 | /// Returns a byte array containing the raw transaction output 81 | public byte[] serialize() throws IOException { 82 | WriteUtils writer = new WriteUtils(); 83 | 84 | //write satoshi value 85 | writer.writeInt64LE(satoshis.longValue()); 86 | 87 | //write the locking script 88 | byte[] outputScript = _lockingScriptBuilder.getLockingScript().getProgram(); 89 | VarInt varInt = new VarInt(outputScript.length); 90 | byte[] varIntBytes = varInt.encode(); 91 | writer.writeBytes(varIntBytes, varIntBytes.length); 92 | 93 | writer.writeBytes(outputScript, outputScript.length); 94 | return writer.getBytes(); 95 | } 96 | 97 | public Script getScript() { 98 | return _lockingScriptBuilder.getLockingScript(); 99 | } 100 | 101 | public BigInteger getAmount() { 102 | return satoshis; 103 | } 104 | public void setAmount(BigInteger amount) { 105 | this.satoshis = amount; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/crypto/LinuxSecureRandom.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.crypto; 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | import java.io.*; 23 | import java.security.Provider; 24 | import java.security.SecureRandomSpi; 25 | import java.security.Security; 26 | 27 | /** 28 | * A SecureRandom implementation that is able to override the standard JVM provided implementation, and which simply 29 | * serves random numbers by reading /dev/urandom. That is, it delegates to the kernel on UNIX systems and is unusable on 30 | * other platforms. Attempts to manually set the seed are ignored. There is no difference between seed bytes and 31 | * non-seed bytes, they are all from the same source. 32 | */ 33 | public class LinuxSecureRandom extends SecureRandomSpi { 34 | private static final FileInputStream urandom; 35 | 36 | private static class LinuxSecureRandomProvider extends Provider { 37 | public LinuxSecureRandomProvider() { 38 | super("LinuxSecureRandom", 1.0, "A Linux specific random number provider that uses /dev/urandom"); 39 | put("SecureRandom.LinuxSecureRandom", LinuxSecureRandom.class.getName()); 40 | } 41 | } 42 | 43 | private static final Logger log = LoggerFactory.getLogger(LinuxSecureRandom.class); 44 | 45 | static { 46 | try { 47 | File file = new File("/dev/urandom"); 48 | // This stream is deliberately leaked. 49 | urandom = new FileInputStream(file); 50 | if (urandom.read() == -1) 51 | throw new RuntimeException("/dev/urandom not readable?"); 52 | // Now override the default SecureRandom implementation with this one. 53 | int position = Security.insertProviderAt(new LinuxSecureRandomProvider(), 1); 54 | 55 | if (position != -1) 56 | log.info("Secure randomness will be read from {} only.", file); 57 | else 58 | log.info("Randomness is already secure."); 59 | } catch (FileNotFoundException e) { 60 | // Should never happen. 61 | log.error("/dev/urandom does not appear to exist or is not openable"); 62 | throw new RuntimeException(e); 63 | } catch (IOException e) { 64 | log.error("/dev/urandom does not appear to be readable"); 65 | throw new RuntimeException(e); 66 | } 67 | } 68 | 69 | private final DataInputStream dis; 70 | 71 | public LinuxSecureRandom() { 72 | // DataInputStream is not thread safe, so each random object has its own. 73 | dis = new DataInputStream(urandom); 74 | } 75 | 76 | @Override 77 | protected void engineSetSeed(byte[] bytes) { 78 | // Ignore. 79 | } 80 | 81 | @Override 82 | protected void engineNextBytes(byte[] bytes) { 83 | try { 84 | dis.readFully(bytes); // This will block until all the bytes can be read. 85 | } catch (IOException e) { 86 | throw new RuntimeException(e); // Fatal error. Do not attempt to recover from this. 87 | } 88 | } 89 | 90 | @Override 91 | protected byte[] engineGenerateSeed(int i) { 92 | byte[] bits = new byte[i]; 93 | engineNextBytes(bits); 94 | return bits; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/address/PrefixedChecksummedBytes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * Copyright 2018 Andreas Schildbach 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.twostack.bitcoin4j.address; 19 | 20 | import org.twostack.bitcoin4j.params.NetworkType; 21 | 22 | import java.io.IOException; 23 | import java.io.ObjectInputStream; 24 | import java.io.ObjectOutputStream; 25 | import java.io.Serializable; 26 | import java.lang.reflect.Field; 27 | import java.util.Arrays; 28 | import java.util.Objects; 29 | 30 | import static com.google.common.base.Preconditions.checkNotNull; 31 | 32 | /** 33 | *

34 | * The following format is often used to represent some type of data (e.g. key or hash of key): 35 | *

36 | * 37 | *
 38 |  * [prefix] [data bytes] [checksum]
 39 |  * 
40 | *

41 | * and the result is then encoded with some variant of base. This format is most commonly used for addresses and private 42 | * keys exported using Bitcoin Core's dumpprivkey command. 43 | *

44 | */ 45 | public abstract class PrefixedChecksummedBytes implements Serializable, Cloneable { 46 | protected final transient NetworkType networkType; 47 | protected final byte[] bytes; 48 | 49 | protected PrefixedChecksummedBytes(NetworkType networkType, byte[] bytes) { 50 | this.networkType = checkNotNull(networkType); 51 | this.bytes = checkNotNull(bytes); 52 | } 53 | 54 | /** 55 | * @return network this data is valid for 56 | */ 57 | public final NetworkType getNetworkType(){ 58 | return networkType; 59 | } 60 | 61 | 62 | @Override 63 | public int hashCode() { 64 | return Objects.hash(networkType, Arrays.hashCode(bytes)); 65 | } 66 | 67 | @Override 68 | public boolean equals(Object o) { 69 | if (this == o) return true; 70 | if (o == null || getClass() != o.getClass()) return false; 71 | PrefixedChecksummedBytes other = (PrefixedChecksummedBytes) o; 72 | return this.networkType.equals(other.networkType) && Arrays.equals(this.bytes, other.bytes); 73 | } 74 | 75 | /** 76 | * This implementation narrows the return type to {@link PrefixedChecksummedBytes} 77 | * and allows subclasses to throw {@link CloneNotSupportedException} even though it 78 | * is never thrown by this implementation. 79 | */ 80 | @Override 81 | public PrefixedChecksummedBytes clone() throws CloneNotSupportedException { 82 | return (PrefixedChecksummedBytes) super.clone(); 83 | } 84 | 85 | // Java serialization 86 | 87 | private void writeObject(ObjectOutputStream out) throws IOException { 88 | out.defaultWriteObject(); 89 | out.writeUTF(networkType.name()); 90 | } 91 | 92 | private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 93 | in.defaultReadObject(); 94 | try { 95 | Field paramsField = PrefixedChecksummedBytes.class.getDeclaredField("networkType"); 96 | paramsField.setAccessible(true); 97 | paramsField.set(this, checkNotNull(NetworkType.valueOf(in.readUTF()))); 98 | paramsField.setAccessible(false); 99 | } catch (NoSuchFieldException | IllegalAccessException x) { 100 | throw new RuntimeException(x); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/utils/ExponentialBackoff.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.utils; 18 | 19 | import org.twostack.bitcoin4j.Utils; 20 | 21 | import static com.google.common.base.Preconditions.checkArgument; 22 | 23 | /** 24 | *

Tracks successes and failures and calculates a time to retry the operation.

25 | * 26 | *

The retries are exponentially backed off, up to a maximum interval. On success the back off interval is reset.

27 | */ 28 | public class ExponentialBackoff implements Comparable { 29 | public static final int DEFAULT_INITIAL_MILLIS = 100; 30 | public static final float DEFAULT_MULTIPLIER = 1.1f; 31 | public static final int DEFAULT_MAXIMUM_MILLIS = 30 * 1000; 32 | 33 | private float backoff; 34 | private long retryTime; 35 | private final Params params; 36 | 37 | /** 38 | * Parameters to configure a particular kind of exponential backoff. 39 | */ 40 | public static class Params { 41 | private final float initial; 42 | private final float multiplier; 43 | private final float maximum; 44 | 45 | /** 46 | * @param initialMillis the initial interval to wait, in milliseconds 47 | * @param multiplier the multiplier to apply on each failure 48 | * @param maximumMillis the maximum interval to wait, in milliseconds 49 | */ 50 | public Params(long initialMillis, float multiplier, long maximumMillis) { 51 | checkArgument(multiplier > 1.0f, "multiplier must be greater than 1.0"); 52 | checkArgument(maximumMillis >= initialMillis, "maximum must not be less than initial"); 53 | 54 | this.initial = initialMillis; 55 | this.multiplier = multiplier; 56 | this.maximum = maximumMillis; 57 | } 58 | 59 | /** 60 | * Construct params with default values. 61 | */ 62 | public Params() { 63 | initial = DEFAULT_INITIAL_MILLIS; 64 | multiplier = DEFAULT_MULTIPLIER; 65 | maximum = DEFAULT_MAXIMUM_MILLIS; 66 | } 67 | } 68 | 69 | public ExponentialBackoff(Params params) { 70 | this.params = params; 71 | trackSuccess(); 72 | } 73 | 74 | /** Track a success - reset back off interval to the initial value */ 75 | public final void trackSuccess() { 76 | backoff = params.initial; 77 | retryTime = Utils.currentTimeMillis(); 78 | } 79 | 80 | /** Track a failure - multiply the back off interval by the multiplier */ 81 | public void trackFailure() { 82 | retryTime = Utils.currentTimeMillis() + (long)backoff; 83 | backoff = Math.min(backoff * params.multiplier, params.maximum); 84 | } 85 | 86 | /** Get the next time to retry, in milliseconds since the epoch */ 87 | public long getRetryTime() { 88 | return retryTime; 89 | } 90 | 91 | @Override 92 | public int compareTo(ExponentialBackoff other) { 93 | // note that in this implementation compareTo() is not consistent with equals() 94 | return Long.compare(retryTime, other.retryTime); 95 | } 96 | 97 | @Override 98 | public String toString() { 99 | return "ExponentialBackoff retry=" + retryTime + " backoff=" + backoff; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/crypto/ChildNumber.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Matija Mazi. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.crypto; 18 | 19 | import java.util.List; 20 | import java.util.Locale; 21 | 22 | /** 23 | *

This is just a wrapper for the i (child number) as per BIP 32 with a boolean getter for the most significant bit 24 | * and a getter for the actual 0-based child number. A {@link List} of these forms a path through a 25 | * {@link DeterministicHierarchy}. This class is immutable. 26 | */ 27 | public class ChildNumber implements Comparable { 28 | /** 29 | * The bit that's set in the child number to indicate whether this key is "hardened". Given a hardened key, it is 30 | * not possible to derive a child public key if you know only the hardened public key. With a non-hardened key this 31 | * is possible, so you can derive trees of public keys given only a public parent, but the downside is that it's 32 | * possible to leak private keys if you disclose a parent public key and a child private key (elliptic curve maths 33 | * allows you to work upwards). 34 | */ 35 | public static final int HARDENED_BIT = 0x80000000; 36 | 37 | public static final ChildNumber ZERO = new ChildNumber(0); 38 | public static final ChildNumber ZERO_HARDENED = new ChildNumber(0, true); 39 | public static final ChildNumber ONE = new ChildNumber(1); 40 | public static final ChildNumber ONE_HARDENED = new ChildNumber(1, true); 41 | 42 | /** Integer i as per BIP 32 spec, including the MSB denoting derivation type (0 = public, 1 = private) **/ 43 | private final int i; 44 | 45 | public ChildNumber(int childNumber, boolean isHardened) { 46 | if (hasHardenedBit(childNumber)) 47 | throw new IllegalArgumentException("Most significant bit is reserved and shouldn't be set: " + childNumber); 48 | i = isHardened ? (childNumber | HARDENED_BIT) : childNumber; 49 | } 50 | 51 | public ChildNumber(int i) { 52 | this.i = i; 53 | } 54 | 55 | /** Returns the uint32 encoded form of the path element, including the most significant bit. */ 56 | public int getI() { 57 | return i; 58 | } 59 | 60 | /** Returns the uint32 encoded form of the path element, including the most significant bit. */ 61 | public int i() { return i; } 62 | 63 | public boolean isHardened() { 64 | return hasHardenedBit(i); 65 | } 66 | 67 | private static boolean hasHardenedBit(int a) { 68 | return (a & HARDENED_BIT) != 0; 69 | } 70 | 71 | /** Returns the child number without the hardening bit set (i.e. index in that part of the tree). */ 72 | public int num() { 73 | return i & (~HARDENED_BIT); 74 | } 75 | 76 | @Override 77 | public String toString() { 78 | return String.format(Locale.US, "%d%s", num(), isHardened() ? "H" : ""); 79 | } 80 | 81 | @Override 82 | public boolean equals(Object o) { 83 | if (this == o) return true; 84 | if (o == null || getClass() != o.getClass()) return false; 85 | return i == ((ChildNumber)o).i; 86 | } 87 | 88 | @Override 89 | public int hashCode() { 90 | return i; 91 | } 92 | 93 | @Override 94 | public int compareTo(ChildNumber other) { 95 | // note that in this implementation compareTo() is not consistent with equals() 96 | return Integer.compare(this.num(), other.num()); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/WriteUtils.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2021 Stephan M. February 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.twostack.bitcoin4j.transaction; 18 | 19 | import java.io.ByteArrayOutputStream; 20 | import java.io.IOException; 21 | import java.math.BigInteger; 22 | 23 | public class WriteUtils { 24 | 25 | private ByteArrayOutputStream bos = new ByteArrayOutputStream(); 26 | 27 | 28 | public void writeBytes(byte[] bytes, int length) { 29 | bos.write(bytes, 0, length); 30 | } 31 | 32 | public void writeUint8LE(int val) throws IOException{ 33 | bos.write((int) (0xFF & val)); 34 | } 35 | 36 | /** Write 2 bytes to the output stream as unsigned 16-bit integer in little endian format. */ 37 | public void writeUint16LE(int val) throws IOException { 38 | bos.write((int) (0xFF & val)); 39 | bos.write((int) (0xFF & (val >> 8))); 40 | } 41 | 42 | /** Write 2 bytes to the output stream as unsigned 16-bit integer in big endian format. */ 43 | public void writeUint16BE(int val) throws IOException { 44 | bos.write((int) (0xFF & (val >> 8))); 45 | bos.write((int) (0xFF & val)); 46 | } 47 | 48 | /** Write 4 bytes to the output stream as unsigned 32-bit integer in little endian format. */ 49 | public void writeUint32LE(long val) throws IOException { 50 | bos.write((int) (0xFF & val)); 51 | bos.write((int) (0xFF & (val >> 8))); 52 | bos.write((int) (0xFF & (val >> 16))); 53 | bos.write((int) (0xFF & (val >> 24))); 54 | } 55 | 56 | /** Write 4 bytes to the output stream as unsigned 32-bit integer in big endian format. */ 57 | public void writeUint32BE(long val) throws IOException { 58 | bos.write((int) (0xFF & (val >> 24))); 59 | bos.write((int) (0xFF & (val >> 16))); 60 | bos.write((int) (0xFF & (val >> 8))); 61 | bos.write((int) (0xFF & val)); 62 | } 63 | 64 | /** Write 8 bytes to the output stream as signed 64-bit integer in little endian format. */ 65 | public void writeInt64LE(long val) throws IOException { 66 | bos.write((int) (0xFF & val)); 67 | bos.write((int) (0xFF & (val >> 8))); 68 | bos.write((int) (0xFF & (val >> 16))); 69 | bos.write((int) (0xFF & (val >> 24))); 70 | bos.write((int) (0xFF & (val >> 32))); 71 | bos.write((int) (0xFF & (val >> 40))); 72 | bos.write((int) (0xFF & (val >> 48))); 73 | bos.write((int) (0xFF & (val >> 56))); 74 | } 75 | 76 | /** Write 8 bytes to the output stream as unsigned 64-bit integer in little endian format. */ 77 | public void writeUint64LE(BigInteger val) throws IOException { 78 | byte[] bytes = val.toByteArray(); 79 | if (bytes.length > 8) { 80 | throw new RuntimeException("Input too large to encode into a uint64"); 81 | } 82 | bytes = reverseBytes(bytes); 83 | bos.write(bytes); 84 | if (bytes.length < 8) { 85 | for (int i = 0; i < 8 - bytes.length; i++) 86 | bos.write(0); 87 | } 88 | } 89 | 90 | 91 | /** 92 | * Returns a copy of the given byte array in reverse order. 93 | */ 94 | public byte[] reverseBytes(byte[] bytes) { 95 | // We could use the XOR trick here but it's easier to understand if we don't. If we find this is really a 96 | // performance issue the matter can be revisited. 97 | byte[] buf = new byte[bytes.length]; 98 | for (int i = 0; i < bytes.length; i++) 99 | buf[i] = bytes[bytes.length - 1 - i]; 100 | return buf; 101 | } 102 | 103 | public byte[] getBytes(){ 104 | return bos.toByteArray(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/ReadUtils.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2021 Stephan M. February 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.twostack.bitcoin4j.transaction; 18 | 19 | import org.twostack.bitcoin4j.Sha256Hash; 20 | import org.twostack.bitcoin4j.Utils; 21 | import org.twostack.bitcoin4j.VarInt; 22 | import org.twostack.bitcoin4j.exception.ProtocolException; 23 | 24 | import java.math.BigInteger; 25 | import java.nio.charset.StandardCharsets; 26 | 27 | public class ReadUtils { 28 | 29 | public static final int MAX_SIZE = 0x02000000; // 32MB 30 | 31 | private byte[] payload; 32 | private int cursor; 33 | 34 | public ReadUtils(byte[] payload){ 35 | this.payload = payload; 36 | cursor = 0; 37 | } 38 | 39 | public long readUint32() throws ProtocolException { 40 | try { 41 | long u = Utils.readUint32(payload, cursor); 42 | cursor += 4; 43 | return u; 44 | } catch (ArrayIndexOutOfBoundsException e) { 45 | throw new ProtocolException(e); 46 | } 47 | } 48 | 49 | public long readInt64() throws ProtocolException { 50 | try { 51 | long u = Utils.readInt64(payload, cursor); 52 | cursor += 8; 53 | return u; 54 | } catch (ArrayIndexOutOfBoundsException e) { 55 | throw new ProtocolException(e); 56 | } 57 | } 58 | 59 | public BigInteger readUint64() throws ProtocolException { 60 | // Java does not have an unsigned 64 bit type. So scrape it off the wire then flip. 61 | return new BigInteger(Utils.reverseBytes(readBytes(8))); 62 | } 63 | 64 | public VarInt readVarInt() throws ProtocolException { 65 | return readVarInt(0); 66 | } 67 | 68 | public VarInt readVarInt(int offset) throws ProtocolException { 69 | try { 70 | VarInt varint = new VarInt(payload, cursor + offset); 71 | cursor += offset + varint.getOriginalSizeInBytes(); 72 | return varint; 73 | } catch (ArrayIndexOutOfBoundsException e) { 74 | throw new ProtocolException(e); 75 | } 76 | } 77 | 78 | private void checkReadLength(int length) throws ProtocolException { 79 | if ((length > MAX_SIZE) || (cursor + length > payload.length)) { 80 | throw new ProtocolException("Claimed value length too large: " + length); 81 | } 82 | } 83 | 84 | public byte[] readBytes(int length) throws ProtocolException { 85 | checkReadLength(length); 86 | try { 87 | byte[] b = new byte[length]; 88 | System.arraycopy(payload, cursor, b, 0, length); 89 | cursor += length; 90 | return b; 91 | } catch (IndexOutOfBoundsException e) { 92 | throw new ProtocolException(e); 93 | } 94 | } 95 | 96 | public byte readByte() throws ProtocolException { 97 | checkReadLength(1); 98 | return payload[cursor++]; 99 | } 100 | 101 | public byte[] readByteArray() throws ProtocolException { 102 | final int length = readVarInt().intValue(); 103 | return readBytes(length); 104 | } 105 | 106 | public String readStr() throws ProtocolException { 107 | int length = readVarInt().intValue(); 108 | return length == 0 ? "" : new String(readBytes(length), StandardCharsets.UTF_8); // optimization for empty strings 109 | } 110 | 111 | public Sha256Hash readHash() throws ProtocolException { 112 | // We have to flip it around, as it's been read off the wire in little endian. 113 | // Not the most efficient way to do this but the clearest. 114 | return Sha256Hash.wrapReversed(readBytes(32)); 115 | } 116 | 117 | public boolean hasMoreBytes() { 118 | return cursor < payload.length; 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/test/resources/org/twostack/bitcoin4j/transaction/multi_input.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "height": 1302774, 4 | "tx_pos": 0, 5 | "tx_hash": "6021cb6367128b5023ba9bb854702b4df51f2824024cc0565d115c8d67640212", 6 | "value": 69000000, 7 | "raw_tx": "0200000001e69f8f1dceb963105b97d348b28e03d2b1fc73bcb526e55464169045135aea6e000000006b483045022100b8f9ffc8451343e95cbf474c20731e94f793ee7a4c6ea29ce5eccb1e49e9292e02201d57a1643c384be0623f78526e0df80c902825b9c9e25e8bf39f03f8c5f2ceda4121032b81c9f5ab74ef03f11cde9d08b62298c0a9cae13cef2e00ac272ad8dc2de5e9feffffff0240db1c04000000001976a914191f99293aedd9f66e090e296abe2c64cabdbc5788ac1028e785190000001976a914c46d5726085e35c170870089f3cfc3c1cdc2a7e488acf5e01300" 8 | }, 9 | { 10 | "height": 1302786, 11 | "tx_pos": 1, 12 | "tx_hash": "8daea1159102af0bee236e4ccb76fdcca20bdaa2070037197d697d938a61a5bb", 13 | "value": 59000000, 14 | "raw_tx": "0200000001120264678d5c115d56c04c0224281ff54d2b7054b89bba23508b126763cb2160010000006b483045022100b36ea238d238dbcea7edb7e8069043e54bb7ec5ad444dc31c41e02a4f61fc191022074957e6dacbeab025b65c4acd1f8496af129e3c5f7aca5a64bebe4f57e2547f94121031307054beaf3ed77541a67ef32b9399864c936ee0d31cdb7c21bfe6131dd958cfeffffff02a8d16282190000001976a91412cc553bb2b46a50051c9961607a9831bbc4b01d88acc0448403000000001976a914191f99293aedd9f66e090e296abe2c64cabdbc5788ac01e11300" 15 | }, 16 | { 17 | "height": 1302825, 18 | "tx_pos": 1, 19 | "tx_hash": "ea71cd8e6106392085988e1f1330d6ee8f69817370a34c11ae6aa6469c69df64", 20 | "value": 31851596, 21 | "raw_tx": "0100000001fc0bfc1c3bbc5a718aea61d056d4eb996bd89dd76aa0496993ec5295d7f63bc5010000006b48304502210083fd75413e630bdf7744fe4a0feb5ef4c1519bd46beb45d1681414cb105673c60220050408b05a95a4d036a365bcc8036f90357ae8b18a11d55d3d715aef5869e24e412102349d8cb65c23eea04a9ef65546f354219a7bf46b598b51d4039fc5b6a1d06503ffffffff0210270000000000001976a9145d1b5fe913e5c1248831de2862beda0a96dc2f7b88ac4c04e601000000001976a914191f99293aedd9f66e090e296abe2c64cabdbc5788ac00000000" 22 | }, 23 | { 24 | "height": 1303205, 25 | "tx_pos": 0, 26 | "tx_hash": "7acd00cea745e55414f8f7077ff69e4e02c1d976b371f1db796d5c6f5252d63d", 27 | "value": 25000000, 28 | "raw_tx": "02000000010de0593ae6b97be495eb73ca41b52f71a7e280323bd5a4cf483319ad730aa6ab000000006a47304402202d3e536eb4ec1e9e9616288b604473744884a7f515536ac3211d9c1612260642022053f55aa07d2062b21268dc52ba19076ebc593fed237223c7e517071ec158902641210343e2aa532f2da689bef82b1b953adeef1b6c160800aa54d2c109e2c3dea5a13afeffffff0240787d01000000001976a914191f99293aedd9f66e090e296abe2c64cabdbc5788ac983d5055160000001976a914379198178de4fa8da125ea619ad151c0e843585f88aca4e21300" 29 | }, 30 | { 31 | "height": 1408662, 32 | "tx_pos": 1, 33 | "tx_hash": "4595b83f87a6e05c3c5ec54f65f8f7853578896b2919aeb790a66e8223a06788", 34 | "value": 18798970, 35 | "raw_tx": "0100000001914c897fc21e0988265ec12ffa8ad06df901bb82647ec2378567ffdda610d032010000006b483045022100ef543516d6d944bf9ee3d5bf216712d5e6b24e00493adf21e973df2b62a81b7902200c364a302f0aa6118a82f054a634b14758cda860420cecc611e78e523244cf3a412102349d8cb65c23eea04a9ef65546f354219a7bf46b598b51d4039fc5b6a1d06503ffffffff0210270000000000001976a9145d1b5fe913e5c1248831de2862beda0a96dc2f7b88ac7ad91e01000000001976a914191f99293aedd9f66e090e296abe2c64cabdbc5788ac00000000" 36 | }, 37 | { 38 | "height": 1423537, 39 | "tx_pos": 1, 40 | "tx_hash": "d3f13e8d110937182e3cef45eaa20a4bb3dcdd32462221dd8d26ab8243c56735", 41 | "value": 4979458, 42 | "raw_tx": "010000000103e60abf8ede0a5ccfb3d5302d94c1bbce71c8d3291798a5a2563aa913ac67a3010000006a4730440220139fcf4338fdf9261dc92a7cf6779b98a8c9dc8a69fca370c3f42859a40497d80220635349eb830bb80e22bf07620c9fe5259ca2ade68fd5a2ca5336501ede24b763412102349d8cb65c23eea04a9ef65546f354219a7bf46b598b51d4039fc5b6a1d06503ffffffff0210270000000000001976a9145d1b5fe913e5c1248831de2862beda0a96dc2f7b88ac02fb4b00000000001976a914191f99293aedd9f66e090e296abe2c64cabdbc5788ac00000000" 43 | }, 44 | { 45 | "height": 1433834, 46 | "tx_pos": 1, 47 | "tx_hash": "c516d3f82cf01a0826ce67618ab82dfdfbb7dd2890e510f31b7da17191b96f3b", 48 | "value": 3827832, 49 | "raw_tx": "0100000001997e0f9f25029b215c2c507c8a748820597a1517fc051ddbb162e8a83bb95038010000006b483045022100ec125b67d99cfb1e8ae4df96b3b962350d796c7320a061ee465886367f6d29840220743b04ef4912b2be8e46bf8969d99ffee7580637f070244767ddce65a5c6944f412102349d8cb65c23eea04a9ef65546f354219a7bf46b598b51d4039fc5b6a1d06503ffffffff02a0860100000000001976a914f5d33ee198ad13840ce410ba96e149e463a6c35288ac78683a00000000001976a914191f99293aedd9f66e090e296abe2c64cabdbc5788ac00000000" 50 | } 51 | ] 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/crypto/PBKDF2SHA512.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Cole Barnes [cryptofreek{at}gmail{dot}com] 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | */ 23 | 24 | package org.twostack.bitcoin4j.crypto; 25 | 26 | import javax.crypto.Mac; 27 | import javax.crypto.spec.SecretKeySpec; 28 | import java.io.ByteArrayOutputStream; 29 | import java.nio.ByteBuffer; 30 | import java.nio.ByteOrder; 31 | import java.nio.charset.StandardCharsets; 32 | 33 | /** 34 | *

This is a clean-room implementation of PBKDF2 using RFC 2898 as a reference.

35 | * 36 | *

RFC 2898: http://tools.ietf.org/html/rfc2898#section-5.2

37 | * 38 | *

This code passes all RFC 6070 test vectors: http://tools.ietf.org/html/rfc6070

39 | * 40 | *

http://cryptofreek.org/2012/11/29/pbkdf2-pure-java-implementation/
41 | * Modified to use SHA-512 - Ken Sedgwick ken@bonsai.com

42 | */ 43 | public class PBKDF2SHA512 { 44 | public static byte[] derive(String P, String S, int c, int dkLen) { 45 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 46 | 47 | try { 48 | int hLen = 20; 49 | 50 | if (dkLen > ((Math.pow(2, 32)) - 1) * hLen) { 51 | throw new IllegalArgumentException("derived key too long"); 52 | } else { 53 | int l = (int) Math.ceil((double) dkLen / (double) hLen); 54 | // int r = dkLen - (l-1)*hLen; 55 | 56 | for (int i = 1; i <= l; i++) { 57 | byte[] T = F(P, S, c, i); 58 | baos.write(T); 59 | } 60 | } 61 | } catch (Exception e) { 62 | throw new RuntimeException(e); 63 | } 64 | 65 | byte[] baDerived = new byte[dkLen]; 66 | System.arraycopy(baos.toByteArray(), 0, baDerived, 0, baDerived.length); 67 | 68 | return baDerived; 69 | } 70 | 71 | private static byte[] F(String P, String S, int c, int i) throws Exception { 72 | byte[] U_LAST = null; 73 | byte[] U_XOR = null; 74 | 75 | SecretKeySpec key = new SecretKeySpec(P.getBytes(StandardCharsets.UTF_8), "HmacSHA512"); 76 | Mac mac = Mac.getInstance(key.getAlgorithm()); 77 | mac.init(key); 78 | 79 | for (int j = 0; j < c; j++) { 80 | if (j == 0) { 81 | byte[] baS = S.getBytes(StandardCharsets.UTF_8); 82 | byte[] baI = INT(i); 83 | byte[] baU = new byte[baS.length + baI.length]; 84 | 85 | System.arraycopy(baS, 0, baU, 0, baS.length); 86 | System.arraycopy(baI, 0, baU, baS.length, baI.length); 87 | 88 | U_XOR = mac.doFinal(baU); 89 | U_LAST = U_XOR; 90 | mac.reset(); 91 | } else { 92 | byte[] baU = mac.doFinal(U_LAST); 93 | mac.reset(); 94 | 95 | for (int k = 0; k < U_XOR.length; k++) { 96 | U_XOR[k] = (byte) (U_XOR[k] ^ baU[k]); 97 | } 98 | 99 | U_LAST = baU; 100 | } 101 | } 102 | 103 | return U_XOR; 104 | } 105 | 106 | private static byte[] INT(int i) { 107 | ByteBuffer bb = ByteBuffer.allocate(4); 108 | bb.order(ByteOrder.BIG_ENDIAN); 109 | bb.putInt(i); 110 | 111 | return bb.array(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/transaction/P2PKHDataLockBuilder.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.transaction; 2 | 3 | import org.twostack.bitcoin4j.Address; 4 | import org.twostack.bitcoin4j.PublicKey; 5 | import org.twostack.bitcoin4j.params.NetworkAddressType; 6 | import org.twostack.bitcoin4j.script.*; 7 | 8 | import java.nio.ByteBuffer; 9 | import java.util.List; 10 | 11 | import static org.twostack.bitcoin4j.script.ScriptOpCodes.*; 12 | import static org.twostack.bitcoin4j.script.ScriptOpCodes.OP_CHECKSIG; 13 | 14 | /** 15 | * A combination of P2PKH and an "OP_PUSHDATA [data] OP_DROP" pre-prended to the 16 | * Locking Script. This results in a spendable output that has data attached. 17 | * The implication here is that spending the output signs over the data. 18 | * 19 | * Combined locking + unlocking script has this shape: 20 | * 21 | * 'OP_PUSHDATA1 32 0x2606168dabed7b4d11fdd242317adb480ee8c4fa7330db1a8b4f1c7749072aea OP_DROP OP_DUP OP_HASH160 20 0x581e5e328b0d34d724c09f123c050b341d11d96c OP_EQUALVERIFY OP_CHECKSIG' 22 | * 23 | */ 24 | public class P2PKHDataLockBuilder extends LockingScriptBuilder{ 25 | 26 | private Address address; 27 | private byte[] pubkeyHash; 28 | 29 | public Address getAddress() { 30 | return address; 31 | } 32 | 33 | public byte[] getPubkeyHash() { 34 | return pubkeyHash; 35 | } 36 | 37 | public ByteBuffer getDataBuffer() { 38 | return dataBuffer; 39 | } 40 | 41 | private ByteBuffer dataBuffer; 42 | 43 | static P2PKHDataLockBuilder fromPublicKey(PublicKey key, ByteBuffer data, NetworkAddressType networkType){ 44 | Address address = Address.fromKey(networkType, key); 45 | return new P2PKHDataLockBuilder(address, data); 46 | } 47 | 48 | public P2PKHDataLockBuilder(Address address, ByteBuffer data){ 49 | this.address = address; 50 | this.dataBuffer = data; 51 | 52 | if (address != null) { 53 | this.pubkeyHash = address.getHash(); //hash160(pubkey) aka pubkeyHash 54 | } 55 | } 56 | 57 | public P2PKHDataLockBuilder(Script script){ 58 | parse(script); 59 | } 60 | 61 | private void parse(Script script){ 62 | 63 | if (script != null) { 64 | 65 | List chunkList = script.getChunks(); 66 | 67 | if (!chunkList.get(0).isPushData() && chunkList.get(1).opcode != OP_DROP){ 68 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR,"Script must start with PUSHDATA & DROP instruction."); 69 | } 70 | 71 | int chunkListOffset = 0; 72 | 73 | if (chunkList.size() == 8){ 74 | chunkListOffset = 1; 75 | } 76 | 77 | if (chunkList.get(chunkListOffset + 4).opcode != 20 ){ 78 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Signature and Public Key values are malformed"); 79 | } 80 | 81 | 82 | if(!( chunkList.get(chunkListOffset + 2).opcode == ScriptOpCodes.OP_DUP && 83 | chunkList.get(chunkListOffset + 3).opcode == ScriptOpCodes.OP_HASH160 && 84 | chunkList.get(chunkListOffset + 5).opcode == ScriptOpCodes.OP_EQUALVERIFY && 85 | chunkList.get(chunkListOffset + 6).opcode == ScriptOpCodes.OP_CHECKSIG )){ 86 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Malformed script. Mismatched OP_CODES."); 87 | } 88 | 89 | this.dataBuffer = ByteBuffer.wrap(chunkList.get(chunkListOffset).data); 90 | 91 | this.pubkeyHash = chunkList.get(chunkListOffset + 4).data; 92 | 93 | }else{ 94 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Invalid Script or Malformed Script."); 95 | } 96 | } 97 | 98 | @Override 99 | public Script getLockingScript() { 100 | 101 | if (this.pubkeyHash == null) { 102 | throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Missing pubkeyHash. Can't construct the script."); 103 | } 104 | 105 | ScriptBuilder builder = new ScriptBuilder(); 106 | builder.data(dataBuffer.array()); 107 | builder.op(OP_DROP); 108 | builder.op(OP_DUP); 109 | builder.op(OP_HASH160); 110 | builder.data(this.pubkeyHash); 111 | builder.op(OP_EQUALVERIFY); 112 | builder.op(OP_CHECKSIG); 113 | 114 | return builder.build(); 115 | 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/crypto/HDKeyDerivationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright by the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.crypto; 18 | 19 | import static org.twostack.bitcoin4j.crypto.HDKeyDerivation.*; 20 | 21 | import org.junit.Test; 22 | import org.twostack.bitcoin4j.Utils; 23 | 24 | import java.math.BigInteger; 25 | 26 | import static org.junit.Assert.*; 27 | 28 | /** 29 | * @author Andreas Schildbach 30 | */ 31 | public class HDKeyDerivationTest { 32 | private static final ChildNumber CHILD_NUMBER = ChildNumber.ONE; 33 | private static final String EXPECTED_CHILD_CHAIN_CODE = "c4341fe988a2ae6240788c6b21df268b9286769915bed23c7649f263b3643ee8"; 34 | private static final String EXPECTED_CHILD_PRIVATE_KEY = "48516d403070bc93f5e4d78c984cf2d71fc9799293b4eeb3de4f88e3892f523d"; 35 | private static final String EXPECTED_CHILD_PUBLIC_KEY = "036d27f617ce7b0cbdce0abebd1c7aafc147bd406276e6a08d64d7a7ed0ca68f0e"; 36 | 37 | @Test 38 | public void testDeriveFromPrivateParent() { 39 | DeterministicKey parent = new DeterministicKey(HDPath.M(), new byte[32], BigInteger.TEN, 40 | null); 41 | assertFalse(parent.isPubKeyOnly()); 42 | 43 | DeterministicKey fromPrivate = HDKeyDerivation.deriveChildKeyFromPrivate(parent, CHILD_NUMBER); 44 | assertEquals(EXPECTED_CHILD_CHAIN_CODE, Utils.HEX.encode(fromPrivate.getChainCode())); 45 | assertEquals(EXPECTED_CHILD_PRIVATE_KEY, fromPrivate.getPrivateKeyAsHex()); 46 | assertEquals(EXPECTED_CHILD_PUBLIC_KEY, fromPrivate.getPublicKeyAsHex()); 47 | assertFalse(fromPrivate.isPubKeyOnly()); 48 | 49 | DeterministicKey fromPublic = HDKeyDerivation.deriveChildKeyFromPublic(parent, CHILD_NUMBER, 50 | HDKeyDerivation.PublicDeriveMode.NORMAL); 51 | assertEquals(EXPECTED_CHILD_CHAIN_CODE, Utils.HEX.encode(fromPublic.getChainCode())); 52 | assertEquals(EXPECTED_CHILD_PRIVATE_KEY, fromPublic.getPrivateKeyAsHex()); 53 | assertEquals(EXPECTED_CHILD_PUBLIC_KEY, fromPublic.getPublicKeyAsHex()); 54 | assertFalse(fromPublic.isPubKeyOnly()); 55 | 56 | DeterministicKey fromPublicWithInversion = HDKeyDerivation.deriveChildKeyFromPublic(parent, CHILD_NUMBER, 57 | HDKeyDerivation.PublicDeriveMode.WITH_INVERSION); 58 | assertEquals(EXPECTED_CHILD_CHAIN_CODE, Utils.HEX.encode(fromPublicWithInversion.getChainCode())); 59 | assertEquals(EXPECTED_CHILD_PRIVATE_KEY, fromPublicWithInversion.getPrivateKeyAsHex()); 60 | assertEquals(EXPECTED_CHILD_PUBLIC_KEY, fromPublicWithInversion.getPublicKeyAsHex()); 61 | assertFalse(fromPublicWithInversion.isPubKeyOnly()); 62 | } 63 | 64 | @Test 65 | public void testDeriveFromPublicParent() { 66 | DeterministicKey parent = new DeterministicKey(HDPath.M(), new byte[32], BigInteger.TEN, 67 | null).dropPrivateBytes(); 68 | assertTrue(parent.isPubKeyOnly()); 69 | 70 | try { 71 | HDKeyDerivation.deriveChildKeyFromPrivate(parent, CHILD_NUMBER); 72 | fail(); 73 | } catch (IllegalArgumentException x) { 74 | // expected 75 | } 76 | 77 | DeterministicKey fromPublic = HDKeyDerivation.deriveChildKeyFromPublic(parent, CHILD_NUMBER, 78 | PublicDeriveMode.NORMAL); 79 | assertEquals(EXPECTED_CHILD_CHAIN_CODE, Utils.HEX.encode(fromPublic.getChainCode())); 80 | assertEquals(EXPECTED_CHILD_PUBLIC_KEY, fromPublic.getPublicKeyAsHex()); 81 | assertTrue(fromPublic.isPubKeyOnly()); 82 | 83 | DeterministicKey fromPublicWithInversion = HDKeyDerivation.deriveChildKeyFromPublic(parent, CHILD_NUMBER, 84 | PublicDeriveMode.WITH_INVERSION); 85 | assertEquals(EXPECTED_CHILD_CHAIN_CODE, Utils.HEX.encode(fromPublicWithInversion.getChainCode())); 86 | assertEquals(EXPECTED_CHILD_PUBLIC_KEY, fromPublicWithInversion.getPublicKeyAsHex()); 87 | assertTrue(fromPublicWithInversion.isPubKeyOnly()); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/script/ScriptBuilderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Nicola Atzei 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.script; 18 | 19 | import org.junit.Test; 20 | 21 | import static org.junit.Assert.*; 22 | 23 | public class ScriptBuilderTest { 24 | 25 | @Test 26 | public void testNumber() { 27 | for (int i = -100; i <= 100; i++) { 28 | Script s = new ScriptBuilder().number(i).build(); 29 | for (ScriptChunk ch : s.chunks) { 30 | assertTrue(Integer.toString(i), ch.isShortestPossiblePushData()); 31 | } 32 | } 33 | } 34 | 35 | @Test 36 | public void numberBuilderZero() { 37 | // Test encoding of zero, which should result in an opcode 38 | final ScriptBuilder builder = new ScriptBuilder(); 39 | 40 | // 0 should encode directly to 0 41 | builder.number(0); 42 | assertArrayEquals(new byte[] { 43 | 0x00 // Pushed data 44 | }, builder.build().getProgram()); 45 | } 46 | 47 | @Test 48 | public void numberBuilderPositiveOpCode() { 49 | final ScriptBuilder builder = new ScriptBuilder(); 50 | 51 | builder.number(5); 52 | assertArrayEquals(new byte[] { 53 | 0x55 // Pushed data 54 | }, builder.build().getProgram()); 55 | } 56 | 57 | @Test 58 | public void numberBuilderBigNum() { 59 | ScriptBuilder builder = new ScriptBuilder(); 60 | // 21066 should take up three bytes including the length byte 61 | // at the start 62 | 63 | builder.number(0x524a); 64 | assertArrayEquals(new byte[] { 65 | 0x02, // Length of the pushed data 66 | 0x4a, 0x52 // Pushed data 67 | }, builder.build().getProgram()); 68 | 69 | // Test the trimming code ignores zeroes in the middle 70 | builder = new ScriptBuilder(); 71 | builder.number(0x110011); 72 | assertEquals(4, builder.build().getProgram().length); 73 | 74 | // Check encoding of a value where signed/unsigned encoding differs 75 | // because the most significant byte is 0x80, and therefore a 76 | // sign byte has to be added to the end for the signed encoding. 77 | builder = new ScriptBuilder(); 78 | builder.number(0x8000); 79 | assertArrayEquals(new byte[] { 80 | 0x03, // Length of the pushed data 81 | 0x00, (byte) 0x80, 0x00 // Pushed data 82 | }, builder.build().getProgram()); 83 | } 84 | 85 | @Test 86 | public void numberBuilderNegative() { 87 | // Check encoding of a negative value 88 | final ScriptBuilder builder = new ScriptBuilder(); 89 | builder.number(-5); 90 | assertArrayEquals(new byte[] { 91 | 0x01, // Length of the pushed data 92 | ((byte) 133) // Pushed data 93 | }, builder.build().getProgram()); 94 | } 95 | 96 | @Test 97 | public void numberBuilder16() { 98 | ScriptBuilder builder = new ScriptBuilder(); 99 | // Numbers greater than 16 must be encoded with PUSHDATA 100 | builder.number(15).number(16).number(17); 101 | builder.number(0, 17).number(1, 16).number(2, 15); 102 | Script script = builder.build(); 103 | assertEquals("PUSHDATA(1)[11] 16 15 15 16 PUSHDATA(1)[11]", script.toString()); 104 | } 105 | 106 | @Test 107 | public void testOpTrue() { 108 | byte[] expected = new byte[] { ScriptOpCodes.OP_TRUE }; 109 | byte[] s = new ScriptBuilder().opTrue().build().getProgram(); 110 | assertArrayEquals(expected, s); 111 | } 112 | 113 | @Test 114 | public void testOpFalse() { 115 | byte[] expected = new byte[] { ScriptOpCodes.OP_FALSE }; 116 | byte[] s = new ScriptBuilder().opFalse().build().getProgram(); 117 | assertArrayEquals(expected, s); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/exception/AddressFormatException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * Copyright 2015 Andreas Schildbach 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.twostack.bitcoin4j.exception; 19 | 20 | import org.twostack.bitcoin4j.address.Base58; 21 | import org.twostack.bitcoin4j.address.PrefixedChecksummedBytes; 22 | 23 | @SuppressWarnings("serial") 24 | public class AddressFormatException extends IllegalArgumentException { 25 | public AddressFormatException() { 26 | super(); 27 | } 28 | 29 | public AddressFormatException(String message) { 30 | super(message); 31 | } 32 | 33 | /** 34 | * This exception is thrown by {@link Base58}, {@link PrefixedChecksummedBytes} hierarchy of 35 | * classes when you try to decode data and a character isn't valid. You shouldn't allow the user to proceed in this 36 | * case. 37 | */ 38 | public static class InvalidCharacter extends AddressFormatException { 39 | public final char character; 40 | public final int position; 41 | 42 | public InvalidCharacter(char character, int position) { 43 | super("Invalid character '" + Character.toString(character) + "' at position " + position); 44 | this.character = character; 45 | this.position = position; 46 | } 47 | } 48 | 49 | /** 50 | * This exception is thrown by {@link Base58}, and the {@link PrefixedChecksummedBytes} hierarchy of 51 | * classes when you try to decode data and the data isn't of the right size. You shouldn't allow the user to proceed 52 | * in this case. 53 | */ 54 | public static class InvalidDataLength extends AddressFormatException { 55 | public InvalidDataLength() { 56 | super(); 57 | } 58 | 59 | public InvalidDataLength(String message) { 60 | super(message); 61 | } 62 | } 63 | 64 | /** 65 | * This exception is thrown by {@link Base58}, and the {@link PrefixedChecksummedBytes} hierarchy of 66 | * classes when you try to decode data and the checksum isn't valid. You shouldn't allow the user to proceed in this 67 | * case. 68 | */ 69 | public static class InvalidChecksum extends AddressFormatException { 70 | public InvalidChecksum() { 71 | super("Checksum does not validate"); 72 | } 73 | 74 | public InvalidChecksum(String message) { 75 | super(message); 76 | } 77 | } 78 | 79 | /** 80 | * This exception is thrown by the {@link PrefixedChecksummedBytes} hierarchy of classes when you try and decode an 81 | * address or private key with an invalid prefix (version header or human-readable part). You shouldn't allow the 82 | * user to proceed in this case. 83 | */ 84 | public static class InvalidPrefix extends AddressFormatException { 85 | public InvalidPrefix() { 86 | super(); 87 | } 88 | 89 | public InvalidPrefix(String message) { 90 | super(message); 91 | } 92 | } 93 | 94 | /** 95 | * This exception is thrown by the {@link PrefixedChecksummedBytes} hierarchy of classes when you try and decode an 96 | * address with a prefix (version header or human-readable part) that used by another network (usually: mainnet vs 97 | * testnet). You shouldn't allow the user to proceed in this case as they are trying to send money across different 98 | * chains, an operation that is guaranteed to destroy the money. 99 | */ 100 | public static class WrongNetwork extends InvalidPrefix { 101 | public WrongNetwork(int versionHeader) { 102 | super("Version code of address did not match acceptable versions for network: " + versionHeader); 103 | } 104 | 105 | public WrongNetwork(String hrp) { 106 | super("Human readable part of address did not match acceptable HRPs for network: " + hrp); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/script/ScriptError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Nicola Atzei 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.script; 18 | 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | 22 | public enum ScriptError { 23 | 24 | SCRIPT_ERR_OK("OK"), 25 | SCRIPT_ERR_UNKNOWN_ERROR("UNKNOWN_ERROR"), 26 | SCRIPT_ERR_EVAL_FALSE("EVAL_FALSE"), 27 | SCRIPT_ERR_OP_RETURN("OP_RETURN"), 28 | SCRIPT_ERR_SPLIT_RANGE("SPLIT_RANGE"), 29 | SCRIPT_ERR_INVALID_NUMBER_RANGE("INVALID_NUMBER_RANGE"), 30 | SCRIPT_ERR_NUMBER_OVERFLOW("SCRIPTNUM_OVERFLOW"), 31 | SCRIPT_ERR_NUMBER_MINENCODE("SCRIPTNUM_MINENCODE"), 32 | SCRIPT_ERR_DIV_BY_ZERO("DIV_BY_ZERO"), 33 | SCRIPT_ERR_MOD_BY_ZERO("MOD_BY_ZERO"), 34 | SCRIPT_ERR_NONCOMPRESSED_PUBKEY("NONCOMPRESSED_PUBKEY"), 35 | SCRIPT_ERR_ILLEGAL_FORKID("ILLEGAL_FORKID"), 36 | SCRIPT_ERR_SIGHASH_FORKID("SIGHASH_FORKID"), 37 | SCRIPT_ERR_MUST_USE_FORKID("MUST_USE_FORKID"), 38 | 39 | /* Max sizes */ 40 | SCRIPT_ERR_SCRIPT_SIZE("SCRIPT_SIZE"), 41 | SCRIPT_ERR_PUSH_SIZE("PUSH_SIZE"), 42 | SCRIPT_ERR_OP_COUNT("OP_COUNT"), 43 | SCRIPT_ERR_STACK_SIZE("STACK_SIZE"), 44 | SCRIPT_ERR_SIG_COUNT("SIG_COUNT"), 45 | SCRIPT_ERR_PUBKEY_COUNT("PUBKEY_COUNT"), 46 | SCRIPT_ERR_OPERAND_SIZE("OPERAND_SIZE"), 47 | 48 | /* Failed verify operations */ 49 | SCRIPT_ERR_VERIFY("VERIFY"), 50 | SCRIPT_ERR_EQUALVERIFY("EQUALVERIFY"), 51 | SCRIPT_ERR_CHECKMULTISIGVERIFY("CHECKMULTISIGVERIFY"), 52 | SCRIPT_ERR_CHECKSIGVERIFY("CHECKSIGVERIFY"), 53 | SCRIPT_ERR_NUMEQUALVERIFY("NUMEQUALVERIFY"), 54 | 55 | /* Logical/Format/Canonical errors */ 56 | SCRIPT_ERR_BAD_OPCODE("BAD_OPCODE"), 57 | SCRIPT_ERR_DISABLED_OPCODE("DISABLED_OPCODE"), 58 | SCRIPT_ERR_INVALID_STACK_OPERATION("INVALID_STACK_OPERATION"), 59 | SCRIPT_ERR_INVALID_ALTSTACK_OPERATION("INVALID_ALTSTACK_OPERATION"), 60 | SCRIPT_ERR_UNBALANCED_CONDITIONAL("UNBALANCED_CONDITIONAL"), 61 | 62 | /* CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY */ 63 | SCRIPT_ERR_NEGATIVE_LOCKTIME("NEGATIVE_LOCKTIME"), 64 | SCRIPT_ERR_UNSATISFIED_LOCKTIME("UNSATISFIED_LOCKTIME"), 65 | 66 | /* Malleability */ 67 | SCRIPT_ERR_SIG_HASHTYPE("SIG_HASHTYPE"), 68 | SCRIPT_ERR_SIG_DER("SIG_DER"), 69 | SCRIPT_ERR_MINIMALDATA("MINIMALDATA"), 70 | SCRIPT_ERR_SIG_PUSHONLY("SIG_PUSHONLY"), 71 | SCRIPT_ERR_SIG_HIGH_S("SIG_HIGH_S"), 72 | SCRIPT_ERR_SIG_NULLDUMMY("SIG_NULLDUMMY"), 73 | SCRIPT_ERR_PUBKEYTYPE("PUBKEYTYPE"), 74 | SCRIPT_ERR_CLEANSTACK("CLEANSTACK"), 75 | SCRIPT_ERR_MINIMALIF("MINIMALIF"), 76 | SCRIPT_ERR_SIG_NULLFAIL("NULLFAIL"), 77 | 78 | /* softfork safeness */ 79 | SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS("DISCOURAGE_UPGRADABLE_NOPS"), 80 | SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), 81 | 82 | /* segregated witness */ 83 | SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH("WITNESS_PROGRAM_WRONG_LENGTH"), 84 | SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY("WITNESS_PROGRAM_WITNESS_EMPTY"), 85 | SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH("WITNESS_PROGRAM_MISMATCH"), 86 | SCRIPT_ERR_WITNESS_MALLEATED("WITNESS_MALLEATED"), 87 | SCRIPT_ERR_WITNESS_MALLEATED_P2SH("WITNESS_MALLEATED_P2SH"), 88 | SCRIPT_ERR_WITNESS_UNEXPECTED("WITNESS_UNEXPECTED"), 89 | SCRIPT_ERR_WITNESS_PUBKEYTYPE("WITNESS_PUBKEYTYPE"), 90 | 91 | SCRIPT_ERR_ERROR_COUNT("ERROR_COUNT"); 92 | 93 | private final String mnemonic; 94 | private static final Map mnemonicToScriptErrorMap; 95 | 96 | private ScriptError(String name) { 97 | this.mnemonic = name; 98 | } 99 | 100 | static { 101 | mnemonicToScriptErrorMap = new HashMap<>(); 102 | for (ScriptError err : ScriptError.values()) { 103 | mnemonicToScriptErrorMap.put(err.getMnemonic(), err); 104 | } 105 | } 106 | 107 | public String getMnemonic() { 108 | return mnemonic; 109 | } 110 | 111 | public static ScriptError fromMnemonic(String name) { 112 | ScriptError err = mnemonicToScriptErrorMap.get(name); 113 | if (err == null) 114 | throw new IllegalArgumentException(name + " is not a valid name"); 115 | return err; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/UnsafeByteArrayOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Steve Coughlan. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j; 18 | 19 | import java.io.ByteArrayOutputStream; 20 | import java.io.IOException; 21 | import java.io.OutputStream; 22 | 23 | /** 24 | *

An unsynchronized implementation of ByteArrayOutputStream that will return the backing byte array if its length == size(). 25 | * This avoids unneeded array copy where the BOS is simply being used to extract a byte array of known length from a 26 | * 'serialized to stream' method.

27 | * 28 | *

Unless the final length can be accurately predicted the only performance this will yield is due to unsynchronized 29 | * methods.

30 | * 31 | * @author git 32 | */ 33 | public class UnsafeByteArrayOutputStream extends ByteArrayOutputStream { 34 | 35 | public UnsafeByteArrayOutputStream() { 36 | super(32); 37 | } 38 | 39 | public UnsafeByteArrayOutputStream(int size) { 40 | super(size); 41 | } 42 | 43 | /** 44 | * Writes the specified byte to this byte array output stream. 45 | * 46 | * @param b the byte to be written. 47 | */ 48 | @Override 49 | public void write(int b) { 50 | int newcount = count + 1; 51 | if (newcount > buf.length) { 52 | buf = copyOf(buf, Math.max(buf.length << 1, newcount)); 53 | } 54 | buf[count] = (byte) b; 55 | count = newcount; 56 | } 57 | 58 | /** 59 | * Writes {@code len} bytes from the specified byte array 60 | * starting at offset {@code off} to this byte array output stream. 61 | * 62 | * @param b the data. 63 | * @param off the start offset in the data. 64 | * @param len the number of bytes to write. 65 | */ 66 | @Override 67 | public void write(byte[] b, int off, int len) { 68 | if ((off < 0) || (off > b.length) || (len < 0) || 69 | ((off + len) > b.length) || ((off + len) < 0)) { 70 | throw new IndexOutOfBoundsException(); 71 | } else if (len == 0) { 72 | return; 73 | } 74 | int newcount = count + len; 75 | if (newcount > buf.length) { 76 | buf = copyOf(buf, Math.max(buf.length << 1, newcount)); 77 | } 78 | System.arraycopy(b, off, buf, count, len); 79 | count = newcount; 80 | } 81 | 82 | /** 83 | * Writes the complete contents of this byte array output stream to 84 | * the specified output stream argument, as if by calling the output 85 | * stream's write method using {@code out.write(buf, 0, count)}. 86 | * 87 | * @param out the output stream to which to write the data. 88 | * @throws IOException if an I/O error occurs. 89 | */ 90 | @Override 91 | public void writeTo(OutputStream out) throws IOException { 92 | out.write(buf, 0, count); 93 | } 94 | 95 | /** 96 | * Resets the {@code count} field of this byte array output 97 | * stream to zero, so that all currently accumulated output in the 98 | * output stream is discarded. The output stream can be used again, 99 | * reusing the already allocated buffer space. 100 | * 101 | * @see java.io.ByteArrayInputStream#count 102 | */ 103 | @Override 104 | public void reset() { 105 | count = 0; 106 | } 107 | 108 | /** 109 | * Creates a newly allocated byte array. Its size is the current 110 | * size of this output stream and the valid contents of the buffer 111 | * have been copied into it. 112 | * 113 | * @return the current contents of this output stream, as a byte array. 114 | * @see ByteArrayOutputStream#size() 115 | */ 116 | @Override 117 | public byte toByteArray()[] { 118 | return count == buf.length ? buf : copyOf(buf, count); 119 | } 120 | 121 | /** 122 | * Returns the current size of the buffer. 123 | * 124 | * @return the value of the {@code count} field, which is the number 125 | * of valid bytes in this output stream. 126 | * @see ByteArrayOutputStream#count 127 | */ 128 | @Override 129 | public int size() { 130 | return count; 131 | } 132 | 133 | private static byte[] copyOf(byte[] in, int length) { 134 | byte[] out = new byte[length]; 135 | System.arraycopy(in, 0, out, 0, Math.min(length, in.length)); 136 | return out; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/params/NetworkParameters.java: -------------------------------------------------------------------------------- 1 | package org.twostack.bitcoin4j.params; 2 | 3 | import org.twostack.bitcoin4j.exception.AddressFormatException; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | 9 | public class NetworkParameters { 10 | 11 | private static int bip32HeaderP2PKHpubTEST = 0x043587cf; // The 4 byte header that serializes in base58 to "tpub". 12 | private static int bip32HeaderP2PKHprivTEST = 0x04358394; // The 4 byte header that serializes in base58 to "tprv" 13 | 14 | private static int bip32HeaderP2PKHpubMAIN = 0x0488b21e; // The 4 byte header that serializes in base58 to "xpub". 15 | private static int bip32HeaderP2PKHprivMAIN = 0x0488ade4; // The 4 byte header that serializes in base58 to "xprv" 16 | 17 | private static int DUMPED_PRIVATE_HEADER_MAIN = 128; 18 | private static int DUMPED_PRIVATE_HEADER_TEST = 239; 19 | 20 | //FIXME: These headers are used for serializing. We don't have TESTNET serialization a.t.m 21 | /** Returns the 4 byte header for BIP32 wallet P2PKH - public key part. */ 22 | public static int getBip32HeaderP2PKHpub(NetworkType networkType) { 23 | 24 | switch (networkType) { 25 | case MAIN: 26 | return bip32HeaderP2PKHpubMAIN; 27 | case TEST: 28 | case REGTEST: 29 | case SCALINGTEST: 30 | return bip32HeaderP2PKHpubTEST; 31 | default: 32 | return bip32HeaderP2PKHpubMAIN; 33 | } 34 | } 35 | 36 | public static int getDumpedPrivateKeyHeader(NetworkType networkType){ 37 | 38 | switch (networkType) { 39 | case MAIN: 40 | return DUMPED_PRIVATE_HEADER_MAIN; 41 | case TEST: 42 | case REGTEST: 43 | case SCALINGTEST: 44 | return DUMPED_PRIVATE_HEADER_TEST; 45 | default: 46 | return DUMPED_PRIVATE_HEADER_MAIN; 47 | } 48 | } 49 | 50 | /** Returns the 4 byte header for BIP32 wallet P2PKH - private key part. */ 51 | public static int getBip32HeaderP2PKHpriv(NetworkType networkType) { 52 | switch (networkType) { 53 | case MAIN: 54 | return bip32HeaderP2PKHprivMAIN; 55 | case TEST: 56 | case REGTEST: 57 | case SCALINGTEST: 58 | return bip32HeaderP2PKHprivTEST; 59 | default: 60 | return bip32HeaderP2PKHprivMAIN; 61 | } 62 | 63 | } 64 | 65 | 66 | 67 | public static List getNetworkTypes(int version){ 68 | switch (version) { 69 | case 0 : 70 | case 5 : 71 | return Arrays.asList(NetworkType.MAIN); 72 | case 111 : 73 | case 196 : 74 | return Arrays.asList(NetworkType.TEST, NetworkType.REGTEST, NetworkType.SCALINGTEST); 75 | 76 | default: 77 | throw new AddressFormatException(version + " is not a valid network type."); 78 | } 79 | } 80 | 81 | public static AddressType getAddressType(int version) { 82 | switch (version) { 83 | case 0 : 84 | case 111 : 85 | return AddressType.PUBKEY_HASH; 86 | case 5 : 87 | case 196 : 88 | return AddressType.SCRIPT_HASH; 89 | 90 | default: 91 | throw new AddressFormatException(version + " is not a valid address type."); 92 | } 93 | } 94 | 95 | 96 | public static int getNetworkVersion(NetworkAddressType type) { 97 | switch (type) { 98 | case MAIN_P2SH: 99 | return 5; 100 | case MAIN_PKH : 101 | return 0; 102 | case TEST_P2SH: 103 | return 196; 104 | case TEST_PKH : 105 | return 111; 106 | default : 107 | return 0; 108 | } 109 | } 110 | 111 | public static NetworkAddressType getNetworkAddressType(int versionByte) { 112 | switch (versionByte) { 113 | case 5 : 114 | return NetworkAddressType.MAIN_P2SH; 115 | case 0 : 116 | return NetworkAddressType.MAIN_PKH; 117 | case 196 : 118 | return NetworkAddressType.TEST_P2SH; 119 | case 111 : 120 | return NetworkAddressType.TEST_PKH; 121 | default: 122 | throw new AddressFormatException(versionByte + " is not a valid address version type."); 123 | } 124 | } 125 | 126 | public static NetworkType getNetworkType(NetworkAddressType networkAddressType) { 127 | 128 | switch (networkAddressType) { 129 | case MAIN_P2SH: 130 | case MAIN_PKH : 131 | return NetworkType.MAIN; 132 | case TEST_P2SH: 133 | case TEST_PKH : 134 | return NetworkType.TEST; 135 | default : 136 | return NetworkType.MAIN; 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/Address.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright by the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j; 18 | 19 | import org.twostack.bitcoin4j.address.LegacyAddress; 20 | import org.twostack.bitcoin4j.address.PrefixedChecksummedBytes; 21 | import org.twostack.bitcoin4j.exception.AddressFormatException; 22 | import org.twostack.bitcoin4j.params.NetworkAddressType; 23 | import org.twostack.bitcoin4j.params.NetworkParameters; 24 | import org.twostack.bitcoin4j.params.NetworkType; 25 | import org.twostack.bitcoin4j.script.Script.ScriptType; 26 | 27 | import javax.annotation.Nullable; 28 | 29 | /** 30 | *

31 | * Base class for addresses, e.g. legacy addresses ({@link org.twostack.bitcoin4j.address.LegacyAddress}). 32 | *

33 | * 34 | *

35 | * Use {@link #fromString(NetworkType, String)} to conveniently construct any kind of address from its textual 36 | * form. 37 | *

38 | */ 39 | public abstract class Address extends PrefixedChecksummedBytes implements Comparable
{ 40 | 41 | protected final transient NetworkAddressType networkAddressType; 42 | 43 | public Address(NetworkAddressType networkAddressType, byte[] bytes) { 44 | super(NetworkParameters.getNetworkType(networkAddressType), bytes); 45 | this.networkAddressType = networkAddressType; 46 | } 47 | 48 | /** 49 | * Construct an address from its textual form. 50 | * 51 | * @param networkType 52 | * the expected network this address is valid for, or null if the network should be derived from the 53 | * textual form 54 | * @param str 55 | * the textual form of the address, such as "17kzeh4N8g49GFvdDzSf8PjaPfyoD1MndL" or 56 | * "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4" 57 | * @return constructed address 58 | * @throws AddressFormatException 59 | * if the given string doesn't parse or the checksum is invalid 60 | * @throws AddressFormatException.WrongNetwork 61 | * if the given string is valid but not for the expected network (eg testnet vs mainnet) 62 | */ 63 | public static Address fromString(@Nullable NetworkType networkType, String str) throws AddressFormatException { 64 | return LegacyAddress.fromBase58(networkType, str); 65 | } 66 | 67 | /** 68 | * Construct an {@link Address} that represents the public part of the given {@link ECKey}. 69 | * 70 | * @param networkType 71 | * network this address is valid for 72 | * @param key 73 | * only the public part is used 74 | * @return constructed address 75 | */ 76 | public static Address fromKey(final NetworkAddressType networkType, final PublicKey key) { 77 | return LegacyAddress.fromKey(networkType, key); 78 | } 79 | 80 | /** 81 | * Get either the public key hash or script hash that is encoded in the address. 82 | * 83 | * @return hash that is encoded in the address 84 | */ 85 | public abstract byte[] getHash(); 86 | 87 | /** 88 | * Get the type of output script that will be used for sending to the address. 89 | * 90 | * @return type of output script 91 | */ 92 | public abstract ScriptType getOutputScriptType(); 93 | 94 | /** 95 | * Comparison field order for addresses is: 96 | *
    97 | *
  1. {@link NetworkAddressType #getId()}
  2. 98 | *
  3. Legacy vs. Segwit
  4. 99 | *
  5. (Legacy only) Version byte
  6. 100 | *
  7. remaining {@code bytes}
  8. 101 | *
102 | *

103 | * Implementations may use {@code compareAddressPartial} for tests 1 and 2. 104 | * 105 | * @param o other {@code Address} object 106 | * @return comparison result 107 | */ 108 | @Override 109 | abstract public int compareTo(Address o); 110 | 111 | /** 112 | * FIXME: Is this needed in absence of Segwit ? 113 | * 114 | * Comparator for the first two comparison fields in {@code Address} comparisons, see {@link Address#compareTo(Address)}. 115 | * Used by {@link LegacyAddress#compareTo(Address)} and { SegwitAddress#compareTo(Address)}. 116 | * 117 | * @param o other {@code Address} object 118 | * @return comparison result 119 | */ 120 | protected int compareAddressPartial(Address o) { 121 | // First compare netParams 122 | int result = this.networkAddressType.compareTo(o.networkAddressType); 123 | return result; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/crypto/DumpedPrivateKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * Copyright 2015 Andreas Schildbach 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.twostack.bitcoin4j.crypto; 19 | 20 | import com.google.common.base.Preconditions; 21 | import org.twostack.bitcoin4j.ECKey; 22 | import org.twostack.bitcoin4j.address.Base58; 23 | import org.twostack.bitcoin4j.address.PrefixedChecksummedBytes; 24 | import org.twostack.bitcoin4j.exception.AddressFormatException; 25 | import org.twostack.bitcoin4j.params.NetworkParameters; 26 | import org.twostack.bitcoin4j.params.NetworkType; 27 | 28 | import javax.annotation.Nullable; 29 | import java.util.Arrays; 30 | 31 | /** 32 | * Parses and generates private keys in the form used by the Bitcoin "dumpprivkey" command. This is the private key 33 | * bytes with a header byte and 4 checksum bytes at the end. If there are 33 private key bytes instead of 32, then 34 | * the last byte is a discriminator value for the compressed pubkey. 35 | */ 36 | public class DumpedPrivateKey extends PrefixedChecksummedBytes { 37 | 38 | /** 39 | * Construct a private key from its Base58 representation. 40 | * @param networkType 41 | * The expected NetworkParameters or null if you don't want validation. 42 | * @param base58 43 | * The textual form of the private key. 44 | * @throws AddressFormatException 45 | * if the given base58 doesn't parse or the checksum is invalid 46 | * @throws AddressFormatException.WrongNetwork 47 | * if the given private key is valid but for a different chain (eg testnet vs mainnet) 48 | * 49 | * @return a private key 50 | */ 51 | public static DumpedPrivateKey fromBase58(@Nullable NetworkType networkType, String base58) 52 | throws AddressFormatException, AddressFormatException.WrongNetwork { 53 | byte[] versionAndDataBytes = Base58.decodeChecked(base58); 54 | int version = versionAndDataBytes[0] & 0xFF; 55 | byte[] bytes = Arrays.copyOfRange(versionAndDataBytes, 1, versionAndDataBytes.length); 56 | if (networkType == null) { 57 | for (NetworkType n : NetworkType.values()) 58 | if (version == NetworkParameters.getDumpedPrivateKeyHeader(n)) 59 | return new DumpedPrivateKey(n, bytes); 60 | throw new AddressFormatException.InvalidPrefix("No network found for version " + version); 61 | } else { 62 | if (version == NetworkParameters.getDumpedPrivateKeyHeader(networkType)) 63 | return new DumpedPrivateKey(networkType, bytes); 64 | throw new AddressFormatException.WrongNetwork(version); 65 | } 66 | } 67 | 68 | private DumpedPrivateKey(NetworkType networkType, byte[] bytes) { 69 | super(networkType, bytes); 70 | if (bytes.length != 32 && bytes.length != 33) 71 | throw new AddressFormatException.InvalidDataLength( 72 | "Wrong number of bytes for a private key (32 or 33): " + bytes.length); 73 | } 74 | 75 | // Used by ECKey.getPrivateKeyEncoded() 76 | public DumpedPrivateKey(NetworkType networkType, byte[] keyBytes, boolean compressed) { 77 | this(networkType, encode(keyBytes, compressed)); 78 | } 79 | 80 | /** 81 | * Returns the base58-encoded textual form, including version and checksum bytes. 82 | * 83 | * @return textual form 84 | */ 85 | public String toBase58() { 86 | return Base58.encodeChecked(NetworkParameters.getDumpedPrivateKeyHeader(networkType), bytes); 87 | } 88 | 89 | private static byte[] encode(byte[] keyBytes, boolean compressed) { 90 | Preconditions.checkArgument(keyBytes.length == 32, "Private keys must be 32 bytes"); 91 | if (!compressed) { 92 | return keyBytes; 93 | } else { 94 | // Keys that have compressed public components have an extra 1 byte on the end in dumped form. 95 | byte[] bytes = new byte[33]; 96 | System.arraycopy(keyBytes, 0, bytes, 0, 32); 97 | bytes[32] = 1; 98 | return bytes; 99 | } 100 | } 101 | 102 | /** 103 | * @return an ECKey created from this encoded private key. 104 | */ 105 | public ECKey getKey() { 106 | return ECKey.fromPrivate(Arrays.copyOf(bytes, 32), isPubKeyCompressed()); 107 | } 108 | 109 | /** 110 | * @return true if the public key corresponding to this private key is compressed. 111 | */ 112 | public boolean isPubKeyCompressed() { 113 | return bytes.length == 33 && bytes[32] == 1; 114 | } 115 | 116 | @Override 117 | public String toString() { 118 | return toBase58(); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/test/java/org/twostack/bitcoin4j/script/ScriptChunkTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Andreas Schildbach 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.twostack.bitcoin4j.script; 18 | 19 | import com.google.common.primitives.Bytes; 20 | import org.junit.Test; 21 | 22 | import java.util.Random; 23 | 24 | import static org.junit.Assert.*; 25 | import static org.twostack.bitcoin4j.script.ScriptOpCodes.*; 26 | 27 | public class ScriptChunkTest { 28 | 29 | private static final Random RANDOM = new Random(42); 30 | 31 | // @Test 32 | // public void equalsContract() { 33 | // EqualsVerifier.forClass(ScriptChunk.class) 34 | // .usingGetClass() 35 | // .verify(); 36 | // } 37 | 38 | @Test 39 | public void testToStringOnInvalidScriptChunk() { 40 | // see https://github.com/bitcoinj/bitcoinj/issues/1860 41 | // In summary: toString() throws when given an invalid ScriptChunk. 42 | // It should perhaps be impossible to even construct such a ScriptChunk, but 43 | // until that is the case, toString() should not throw. 44 | ScriptChunk pushWithoutData = new ScriptChunk(OP_PUSHDATA1, null); 45 | 46 | // the chunk is invalid, but at least we can determine its opcode 47 | assertEquals("PUSHDATA1", pushWithoutData.toString()); 48 | } 49 | 50 | @Test 51 | public void testShortestPossibleDataPush() { 52 | assertTrue("empty push", new ScriptBuilder().data(new byte[0]).build().getChunks().get(0) 53 | .isShortestPossiblePushData()); 54 | 55 | for (byte i = -1; i < 127; i++) 56 | assertTrue("push of single byte " + i, new ScriptBuilder().data(new byte[] { i }).build().getChunks() 57 | .get(0).isShortestPossiblePushData()); 58 | 59 | // for (int len = 2; len < Script.MAX_SCRIPT_ELEMENT_SIZE; len++) 60 | // assertTrue("push of " + len + " bytes", new ScriptBuilder().data(new byte[len]).build().getChunks().get(0) 61 | // .isShortestPossiblePushData()); 62 | 63 | // non-standard chunks 64 | for (byte i = 1; i <= 16; i++) 65 | assertFalse("push of smallnum " + i, new ScriptChunk(1, new byte[] { i }).isShortestPossiblePushData()); 66 | assertFalse("push of 75 bytes", new ScriptChunk(OP_PUSHDATA1, new byte[75]).isShortestPossiblePushData()); 67 | assertFalse("push of 255 bytes", new ScriptChunk(OP_PUSHDATA2, new byte[255]).isShortestPossiblePushData()); 68 | assertFalse("push of 65535 bytes", new ScriptChunk(OP_PUSHDATA4, new byte[65535]).isShortestPossiblePushData()); 69 | } 70 | 71 | @Test 72 | public void testToByteArray_opcode() { 73 | byte[] expected = new byte[] { OP_IF }; 74 | byte[] actual = new ScriptChunk(OP_IF, null).toByteArray(); 75 | assertArrayEquals(expected, actual); 76 | } 77 | 78 | @Test 79 | public void testToByteArray_smallNum() { 80 | byte[] expected = new byte[] { OP_0 }; 81 | byte[] actual = new ScriptChunk(OP_0, null).toByteArray(); 82 | assertArrayEquals(expected, actual); 83 | } 84 | 85 | @Test 86 | public void testToByteArray_lt_OP_PUSHDATA1() { 87 | // < OP_PUSHDATA1 88 | for (byte len = 1; len < OP_PUSHDATA1; len++) { 89 | byte[] bytes = new byte[len]; 90 | RANDOM.nextBytes(bytes); 91 | byte[] expected = Bytes.concat(new byte[] { len }, bytes); 92 | byte[] actual = new ScriptChunk(len, bytes).toByteArray(); 93 | assertArrayEquals(expected, actual); 94 | } 95 | } 96 | 97 | @Test 98 | public void testToByteArray_OP_PUSHDATA1() { 99 | // OP_PUSHDATA1 100 | byte[] bytes = new byte[0xFF]; 101 | RANDOM.nextBytes(bytes); 102 | byte[] expected = Bytes.concat(new byte[] { OP_PUSHDATA1, (byte) 0xFF }, bytes); 103 | byte[] actual = new ScriptChunk(OP_PUSHDATA1, bytes).toByteArray(); 104 | assertArrayEquals(expected, actual); 105 | } 106 | 107 | @Test 108 | public void testToByteArray_OP_PUSHDATA2() { 109 | // OP_PUSHDATA2 110 | byte[] bytes = new byte[0x0102]; 111 | RANDOM.nextBytes(bytes); 112 | byte[] expected = Bytes.concat(new byte[] { OP_PUSHDATA2, 0x02, 0x01 }, bytes); 113 | byte[] actual = new ScriptChunk(OP_PUSHDATA2, bytes).toByteArray(); 114 | assertArrayEquals(expected, actual); 115 | } 116 | 117 | @Test 118 | public void testToByteArray_OP_PUSHDATA4() { 119 | // OP_PUSHDATA4 120 | byte[] bytes = new byte[0x0102]; 121 | RANDOM.nextBytes(bytes); 122 | byte[] expected = Bytes.concat(new byte[] { OP_PUSHDATA4, 0x02, 0x01, 0x00, 0x00 }, bytes); 123 | byte[] actual = new ScriptChunk(OP_PUSHDATA4, bytes).toByteArray(); 124 | assertArrayEquals(expected, actual); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/PrivateKey.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2021 Stephan M. February 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.twostack.bitcoin4j; 18 | 19 | import org.twostack.bitcoin4j.address.Base58; 20 | import org.twostack.bitcoin4j.exception.InvalidKeyException; 21 | import org.twostack.bitcoin4j.params.NetworkType; 22 | import org.twostack.bitcoin4j.transaction.ReadUtils; 23 | 24 | import java.math.BigInteger; 25 | import java.util.Arrays; 26 | 27 | public class PrivateKey { 28 | 29 | ECKey key; 30 | boolean _hasCompressedPubKey; 31 | NetworkType _networkType; 32 | 33 | public PrivateKey() { 34 | this(new ECKey(), true, NetworkType.MAIN); 35 | } 36 | 37 | public PrivateKey(ECKey key){ 38 | this(key, true, NetworkType.MAIN); 39 | } 40 | 41 | public PrivateKey(ECKey key, boolean isCompressed, NetworkType networkType) { 42 | this.key = key; 43 | this._hasCompressedPubKey = isCompressed; 44 | this._networkType = networkType; 45 | } 46 | 47 | public byte[] sign(byte[] buffer){ 48 | ECKey.ECDSASignature sig = this.key.sign(Sha256Hash.wrap(buffer)) ; 49 | return sig.encodeToDER(); 50 | } 51 | 52 | public String toWIF(){ 53 | return key.getPrivateKeyAsWiF(_networkType); 54 | } 55 | 56 | //FIXME: We can use DumpedPrivateKey to replace the internals here 57 | public static PrivateKey fromWIF(String wif) throws InvalidKeyException { 58 | 59 | boolean isCompressed = false; 60 | 61 | if (wif.length() != 51 && wif.length() != 52){ 62 | throw new InvalidKeyException("Valid keys are either 51 or 52 bytes in length"); 63 | } 64 | 65 | //decode from base58 66 | byte[] versionAndDataBytes = Base58.decodeChecked(wif); 67 | 68 | NetworkType networkType = decodeNetworkType(wif); 69 | 70 | //strip first byte 71 | ReadUtils reader = new ReadUtils(versionAndDataBytes); 72 | byte version = reader.readByte(); 73 | byte[] dataBytes = reader.readBytes(versionAndDataBytes.length - 1); 74 | 75 | byte[] keyBytes = dataBytes.clone(); 76 | if (dataBytes.length == 33){ 77 | //drop last byte 78 | //throw error if last byte is not 0x01 to indicate compression 79 | if (dataBytes[32] != 0x01) { 80 | throw new InvalidKeyException("Compressed keys must have last byte set as 0x01. Yours is [" + dataBytes[32] + "]"); 81 | } 82 | 83 | keyBytes = new ReadUtils(dataBytes).readBytes(32); 84 | isCompressed = true; 85 | } 86 | 87 | String keyHex = Utils.HEX.encode(keyBytes); 88 | BigInteger d = new BigInteger(keyHex, 16); 89 | 90 | ECKey key = ECKey.fromPrivate(d); 91 | 92 | return new PrivateKey(key, isCompressed, networkType); 93 | } 94 | 95 | public String toWif(NetworkType networkType){ 96 | return this.key.getPrivateKeyAsWiF(networkType); 97 | } 98 | 99 | 100 | private static NetworkType decodeNetworkType(String wifKey) throws InvalidKeyException{ 101 | 102 | switch (wifKey.charAt(0)){ 103 | case '5' : { 104 | if (wifKey.length() != 51) { 105 | throw new InvalidKeyException("Uncompressed private keys have a length of 51 bytes"); 106 | } 107 | 108 | return NetworkType.MAIN; 109 | } 110 | case '9' : { 111 | if (wifKey.length() != 51) { 112 | throw new InvalidKeyException("Uncompressed private keys have a length of 51 bytes"); 113 | } 114 | 115 | return NetworkType.TEST; 116 | } 117 | case 'L' : case 'K' : { 118 | if (wifKey.length() != 52) { 119 | throw new InvalidKeyException("Compressed private keys have a length of 52 bytes"); 120 | } 121 | 122 | return NetworkType.MAIN; 123 | } 124 | case 'c' : { 125 | if (wifKey.length() != 52) { 126 | throw new InvalidKeyException("Compressed private keys have a length of 52 bytes"); 127 | } 128 | 129 | return NetworkType.TEST; 130 | } 131 | default : { 132 | throw new InvalidKeyException("Address WIF format must start with either [5] , [9], [L], [K] or [c]"); 133 | } 134 | 135 | } 136 | } 137 | 138 | /** 139 | * @return the PublicKey corresponding to this PrivateKey 140 | */ 141 | public PublicKey getPublicKey() { 142 | return PublicKey.fromHex(Utils.HEX.encode(key.getPubKey())); 143 | } 144 | 145 | 146 | /** 147 | * @return the ECKey backing this private key. 148 | */ 149 | public ECKey getKey() { 150 | return this.key; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/main/java/org/twostack/bitcoin4j/VarInt.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * Copyright 2021 Andreas Schildbach 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.twostack.bitcoin4j; 19 | 20 | import com.google.common.primitives.Ints; 21 | 22 | import java.io.ByteArrayInputStream; 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | 26 | /** 27 | * A variable-length encoded unsigned integer using Satoshi's encoding (a.k.a. "CompactSize"). 28 | */ 29 | public class VarInt { 30 | /** @deprecated use {{@link #intValue()} or {{@link #longValue()}}} */ 31 | @Deprecated 32 | public final long value; 33 | private final int originallyEncodedSize; 34 | 35 | /** 36 | * Constructs a new VarInt with the given unsigned long value. 37 | * 38 | * @param value the unsigned long value (beware widening conversion of negatives!) 39 | */ 40 | public VarInt(long value) { 41 | this.value = value; 42 | originallyEncodedSize = getSizeInBytes(); 43 | } 44 | 45 | /** 46 | * Constructs a new VarInt with the value parsed from the specified offset of the given buffer. 47 | * 48 | * @param buf the buffer containing the value 49 | * @param offset the offset of the value 50 | */ 51 | public VarInt(byte[] buf, int offset) { 52 | int first = 0xFF & buf[offset]; 53 | if (first < 253) { 54 | value = first; 55 | originallyEncodedSize = 1; // 1 data byte (8 bits) 56 | } else if (first == 253) { 57 | value = Utils.readUint16(buf, offset + 1); 58 | originallyEncodedSize = 3; // 1 marker + 2 data bytes (16 bits) 59 | } else if (first == 254) { 60 | value = Utils.readUint32(buf, offset + 1); 61 | originallyEncodedSize = 5; // 1 marker + 4 data bytes (32 bits) 62 | } else { 63 | value = Utils.readInt64(buf, offset + 1); 64 | originallyEncodedSize = 9; // 1 marker + 8 data bytes (64 bits) 65 | } 66 | } 67 | 68 | public static VarInt fromStream(InputStream stream) throws IOException { 69 | int first = 0xFF & stream.read(); 70 | long value; 71 | if (first < 253) { 72 | value = first; 73 | } else if (first == 253) { 74 | value = Utils.readUint16FromStream(stream); 75 | } else if (first == 254) { 76 | value = Utils.readUint32FromStream(stream); 77 | } else { 78 | value = Utils.readInt64FromStream(stream); 79 | } 80 | 81 | return new VarInt(value); 82 | } 83 | 84 | public long longValue() { 85 | return value; 86 | } 87 | 88 | public int intValue() { 89 | return Ints.checkedCast(value); 90 | } 91 | 92 | /** 93 | * Returns the original number of bytes used to encode the value if it was 94 | * deserialized from a byte array, or the minimum encoded size if it was not. 95 | */ 96 | public int getOriginalSizeInBytes() { 97 | return originallyEncodedSize; 98 | } 99 | 100 | /** 101 | * Returns the minimum encoded size of the value. 102 | */ 103 | public final int getSizeInBytes() { 104 | return sizeOf(value); 105 | } 106 | 107 | /** 108 | * Returns the minimum encoded size of the given unsigned long value. 109 | * 110 | * @param value the unsigned long value (beware widening conversion of negatives!) 111 | */ 112 | public static int sizeOf(long value) { 113 | // if negative, it's actually a very large unsigned long value 114 | if (value < 0) return 9; // 1 marker + 8 data bytes 115 | if (value < 253) return 1; // 1 data byte 116 | if (value <= 0xFFFFL) return 3; // 1 marker + 2 data bytes 117 | if (value <= 0xFFFFFFFFL) return 5; // 1 marker + 4 data bytes 118 | return 9; // 1 marker + 8 data bytes 119 | } 120 | 121 | /** 122 | * Encodes the value into its minimal representation. 123 | * 124 | * @return the minimal encoded bytes of the value 125 | */ 126 | public byte[] encode() { 127 | byte[] bytes; 128 | switch (sizeOf(value)) { 129 | case 1: 130 | return new byte[]{(byte) value}; 131 | case 3: 132 | bytes = new byte[3]; 133 | bytes[0] = (byte) 253; 134 | Utils.uint16ToByteArrayLE((int) value, bytes, 1); 135 | return bytes; 136 | case 5: 137 | bytes = new byte[5]; 138 | bytes[0] = (byte) 254; 139 | Utils.uint32ToByteArrayLE(value, bytes, 1); 140 | return bytes; 141 | default: 142 | bytes = new byte[9]; 143 | bytes[0] = (byte) 255; 144 | Utils.int64ToByteArrayLE(value, bytes, 1); 145 | return bytes; 146 | } 147 | } 148 | } 149 | --------------------------------------------------------------------------------