From 06556c673a92a37d023c11b727d97f2708149102 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 2 Sep 2016 15:53:45 +0200 Subject: [PATCH] Use correct crypto curve for DH --- opret-testapp/pom.xml | 22 +- .../java/org/tcpid/opretj/testapp/App.java | 221 ++++++++++-------- .../org/tcpid/opretj/testapp/SigningKey.java | 94 ++++++++ .../org/tcpid/opretj/testapp/VerifyKey.java | 68 ++++++ .../java/org/tcpid/opretj/OPRETECParser.java | 69 ++---- .../org/tcpid/opretj/OPRETTransaction.java | 13 +- 6 files changed, 323 insertions(+), 164 deletions(-) create mode 100644 opret-testapp/src/main/java/org/tcpid/opretj/testapp/SigningKey.java create mode 100644 opret-testapp/src/main/java/org/tcpid/opretj/testapp/VerifyKey.java diff --git a/opret-testapp/pom.xml b/opret-testapp/pom.xml index 62b6ed3..1a61de9 100644 --- a/opret-testapp/pom.xml +++ b/opret-testapp/pom.xml @@ -7,7 +7,16 @@ 0.0.1-SNAPSHOT opret-testapp - + + + oss-sonatype + oss-sonatype + https://oss.sonatype.org/content/repositories/snapshots/ + + true + + + @@ -29,11 +38,12 @@ 1.0.13 - - org.abstractj.kalium - kalium - 0.5.0 - + + com.github.joshjdevl.libsodiumjni + libsodium-jni + 1.0.2-SNAPSHOT + jar + org.tcpid diff --git a/opret-testapp/src/main/java/org/tcpid/opretj/testapp/App.java b/opret-testapp/src/main/java/org/tcpid/opretj/testapp/App.java index d2538c9..9c93344 100644 --- a/opret-testapp/src/main/java/org/tcpid/opretj/testapp/App.java +++ b/opret-testapp/src/main/java/org/tcpid/opretj/testapp/App.java @@ -1,34 +1,33 @@ package org.tcpid.opretj.testapp; import static org.bitcoinj.script.ScriptOpCodes.OP_RETURN; +import static org.libsodium.jni.SodiumConstants.NONCE_BYTES; +import static org.libsodium.jni.SodiumConstants.SECRETKEY_BYTES; import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.Arrays; -import org.abstractj.kalium.crypto.Box; -import org.abstractj.kalium.crypto.Hash; -import org.abstractj.kalium.keys.KeyPair; -import org.abstractj.kalium.keys.PublicKey; -import org.abstractj.kalium.keys.SigningKey; -import org.abstractj.kalium.keys.VerifyKey; +import org.bitcoinj.core.Address; +import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.Coin; import org.bitcoinj.core.InsufficientMoneyException; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.Transaction; -import org.bitcoinj.core.TransactionConfidence; -import org.bitcoinj.core.TransactionOutput; import org.bitcoinj.core.Utils; import org.bitcoinj.script.Script; import org.bitcoinj.script.ScriptBuilder; import org.bitcoinj.utils.Threading; -import org.bitcoinj.wallet.KeyChain.KeyPurpose; import org.bitcoinj.wallet.SendRequest; -import org.bitcoinj.wallet.Wallet.SendResult; +import org.libsodium.jni.crypto.Box; +import org.libsodium.jni.crypto.Hash; +import org.libsodium.jni.keys.KeyPair; +import org.libsodium.jni.keys.PublicKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.tcpid.opretj.OPRETECParser; @@ -45,40 +44,46 @@ import joptsimple.OptionSet; import joptsimple.OptionSpec; public class App { - private static final Logger logger = LoggerFactory.getLogger(App.class); + public static final Hash HASH = new Hash(); + public final static long OPRET_BIRTHDAY = 1471989600; - public static final long OPRET_BIRTHDAY = 1471989600; - static byte[] rawKey = Sha256Hash.hash("TESTSEED".getBytes()); - static SigningKey sk = new SigningKey(rawKey); - static VerifyKey v = sk.getVerifyKey(); - private static byte[] pkhash = Sha256Hash.hash(v.toBytes()); - static byte[] revokemsg = Bytes.concat("Revoke ".getBytes(), pkhash); + private final static Logger logger = LoggerFactory.getLogger(App.class); + private final static SigningKey SK = new SigningKey(HASH.sha256("TESTSEED".getBytes())); + private final static VerifyKey VK = SK.getVerifyKey(); + private final static byte[] PKHASH = HASH.sha256(VK.toBytes()); + private final static byte[] REVOKEMSG = Bytes.concat("Revoke ".getBytes(), PKHASH); public static void checkKey(final byte[] pkhash, final byte[] sig) { - logger.warn("CHECKING REVOKE PK {} - SIG {}", Utils.HEX.encode(pkhash), Utils.HEX.encode(sig)); + logger.warn("CHECKING REVOKE PKHASH {} - SIG {}", Utils.HEX.encode(pkhash), Utils.HEX.encode(sig)); - if (!Arrays.equals(App.pkhash, pkhash)) { + if (!Arrays.equals(Arrays.copyOfRange(App.PKHASH, 0, 12), pkhash)) { logger.warn("Unknown PK {}", Utils.HEX.encode(pkhash)); return; } - logger.warn("Using VerifyKey {}", v); + logger.warn("Using VerifyKey {}", VK); - if (v.verify(revokemsg, sig)) { - logger.warn("REVOKED VerifyKey {}", v); + if (VK.verify(REVOKEMSG, sig)) { + logger.warn("REVOKED VerifyKey {}", VK); } else { logger.warn("SIGNATURE does not match!"); } } private static boolean cryptoSelfTest() { - final KeyPair MKpair = new KeyPair(); - final KeyPair VKpair = new KeyPair(); + final SigningKey msk = new SigningKey(); + + final KeyPair mkpair = msk.getKeyPair(); + final KeyPair vkpair = SK.getKeyPair(); final byte[] nonce = Arrays.copyOfRange(Sha256Hash.hash("TEST".getBytes()), 0, 8); - final byte[] cipher = doubleEnc(MKpair, VKpair, "TEST".getBytes(), nonce); + final byte[] cipher = doubleEnc(mkpair, vkpair, "TEST".getBytes(), nonce); // System.err.println("Cipher len: " + cipher.length); - final byte[] chk = doubleDec(MKpair.getPublicKey(), VKpair.getPublicKey(), cipher, nonce); - return Arrays.equals(chk, "TEST".getBytes()); + try { + final byte[] chk = doubleDec(msk.getVerifyKey().getPublicKey(), VK.getPublicKey(), cipher, nonce); + return Arrays.equals(chk, "TEST".getBytes()); + } catch (final Exception e) { + return false; + } } private static void displayBalance(final OPRETWalletAppKit kit, final PrintWriter out) { @@ -101,21 +106,21 @@ public class App { } private static byte[] doubleDec(final PublicKey MK, final PublicKey VK, final byte[] cipher, final byte[] nonce) { - final Hash h = new Hash(); final KeyPair Epair = new KeyPair( - Arrays.copyOfRange(h.blake2(Bytes.concat(nonce, VK.toBytes(), MK.toBytes())), 0, 32)); + Arrays.copyOfRange(HASH.sha256(Bytes.concat(nonce, VK.toBytes(), MK.toBytes())), 0, SECRETKEY_BYTES)); - final Box boxVK = new Box(VK.toBytes(), Epair.getPrivateKey().toBytes()); - final byte[] nonceVK = Arrays - .copyOfRange(h.blake2(Bytes.concat(nonce, Epair.getPrivateKey().toBytes(), VK.toBytes())), 0, 24); + final Box boxVK = new Box(VK, Epair.getPrivateKey()); + + final byte[] nonceVK = Arrays.copyOfRange( + HASH.sha256(Bytes.concat(nonce, Epair.getPrivateKey().toBytes(), VK.toBytes())), 0, NONCE_BYTES); final byte[] cipherMK = boxVK.decrypt(nonceVK, cipher); - final Box boxMK = new Box(MK.toBytes(), Epair.getPrivateKey().toBytes()); + final Box boxMK = new Box(MK, Epair.getPrivateKey()); - final byte[] nonceMK = Arrays - .copyOfRange(h.blake2(Bytes.concat(nonce, Epair.getPrivateKey().toBytes(), MK.toBytes())), 0, 24); + final byte[] nonceMK = Arrays.copyOfRange( + HASH.sha256(Bytes.concat(nonce, Epair.getPrivateKey().toBytes(), MK.toBytes())), 0, NONCE_BYTES); final byte[] clear = boxMK.decrypt(nonceMK, cipherMK); @@ -124,22 +129,27 @@ public class App { private static byte[] doubleEnc(final KeyPair MKpair, final KeyPair VKpair, final byte[] clear, final byte[] nonce) { - final Hash h = new Hash(); final KeyPair Epair = new KeyPair(Arrays.copyOfRange( - h.blake2(Bytes.concat(nonce, VKpair.getPublicKey().toBytes(), MKpair.getPublicKey().toBytes())), 0, - 32)); + HASH.sha256(Bytes.concat(nonce, VKpair.getPublicKey().toBytes(), MKpair.getPublicKey().toBytes())), 0, + SECRETKEY_BYTES)); + + final Box boxMK = new Box(Epair.getPublicKey(), MKpair.getPrivateKey()); - final Box boxMK = new Box(Epair.getPublicKey().toBytes(), MKpair.getPrivateKey().toBytes()); final byte[] nonceMK = Arrays.copyOfRange( - h.blake2(Bytes.concat(nonce, Epair.getPrivateKey().toBytes(), MKpair.getPublicKey().toBytes())), 0, 24); + HASH.sha256(Bytes.concat(nonce, Epair.getPrivateKey().toBytes(), MKpair.getPublicKey().toBytes())), 0, + NONCE_BYTES); final byte[] cipherMK = boxMK.encrypt(nonceMK, clear); - final Box boxVK = new Box(Epair.getPublicKey().toBytes(), VKpair.getPrivateKey().toBytes()); + final Box boxVK = new Box(Epair.getPublicKey(), VKpair.getPrivateKey()); + final byte[] nonceVK = Arrays.copyOfRange( - h.blake2(Bytes.concat(nonce, Epair.getPrivateKey().toBytes(), VKpair.getPublicKey().toBytes())), 0, 24); + HASH.sha256(Bytes.concat(nonce, Epair.getPrivateKey().toBytes(), VKpair.getPublicKey().toBytes())), 0, + NONCE_BYTES); + final byte[] cipherVK = boxVK.encrypt(nonceVK, cipherMK); + return cipherVK; } @@ -167,7 +177,6 @@ public class App { } private static void handleConsole(final OPRETWalletAppKit kit) throws IOException { - final String receiveStr = kit.wallet().freshReceiveAddress().toString(); final ConsoleReader reader = new ConsoleReader(); final String[] cmds = { "help", "quit", "exit", "balance", "receive", "empty", "opret" }; reader.addCompleter(new StringsCompleter(cmds)); @@ -178,13 +187,17 @@ public class App { displayBalance(kit, out); while ((line = reader.readLine()) != null) { - final String[] argv = line.split("\\s"); + String[] argv = line.split("\\s"); if (argv.length == 0) { continue; } final String cmd = argv[0]; - final String args[] = Arrays.copyOfRange(argv, 1, argv.length); + if (cmd.isEmpty()) { + continue; + } + + argv = Arrays.copyOfRange(argv, 1, argv.length); switch (cmd.toLowerCase()) { case "quit": @@ -196,6 +209,8 @@ public class App { displayBalance(kit, out); break; case "receive": + final String receiveStr = kit.wallet().freshReceiveAddress().toString(); + out.write("send money to: " + receiveStr + "\n"); try { out.write(executeCommand("qrencode -t UTF8 -o - " + receiveStr)); @@ -205,14 +220,31 @@ public class App { out.flush(); break; case "empty": - if (args.length != 1) { - out.println("empty needs a receive address!"); + if (argv.length != 1) { + out.println("'empty
' needs a valid receive address!"); continue; } + out.println("'" + argv[0] + "'"); + out.flush(); + try { + final SendRequest request = SendRequest.emptyWallet(Address.fromBase58(kit.params(), argv[0])); + try { + kit.wallet().sendCoins(request); + } catch (final InsufficientMoneyException e) { + out.println(e.getLocalizedMessage()); + out.flush(); + } + } catch (final AddressFormatException e) { + out.println(e.getLocalizedMessage()); + out.flush(); + } break; case "opret": sendOPReturn(kit, out); break; + default: + out.println("Unknown command. Use 'help' to display available commands."); + break; } } } @@ -256,7 +288,7 @@ public class App { earliestTime = Utils.currentTimeSeconds(); } - bs.addOPRET(pkhash, earliestTime); + bs.addOPRET(Arrays.copyOfRange(App.PKHASH, 0, 12), earliestTime); // bs.addOPRET(Sha256Hash.hash("test1".getBytes()), earliestTime); // bs.addOPRET(Utils.HEX.decode("0f490dee643b01b06e0ea84c253a90050a3543cfb7c74319fb47b04afee5b872"), // earliestTime); @@ -274,7 +306,10 @@ public class App { if (params.getId().equals(NetworkParameters.ID_REGTEST)) { kit.connectToLocalHost(); } - kit.setCheckpoints(App.class.getResourceAsStream("/" + params.getId() + ".checkpoints")); + final InputStream is = App.class.getResourceAsStream("/" + params.getId() + ".checkpoints"); + if (is != null) { + kit.setCheckpoints(is); + } kit.startAsync(); System.out.println("Please wait for the blockchain to be downloaded!"); @@ -292,23 +327,40 @@ public class App { final OPRETWallet wallet = kit.opretwallet(); wallet.addCoinsReceivedEventListener((wallet1, tx, prevBalance, newBalance) -> { - System.out.println("-----> coins resceived: " + tx.getHashAsString()); - System.out.println("received: " + tx.getValue(wallet1)); + final Coin c = tx.getValue(wallet1); + + if (c.isPositive()) { + System.out.println("-----> coins received: " + tx.getHashAsString()); + System.out.println("received: " + c); + } else { + System.out.println("-----> coins sent: " + tx.getHashAsString()); + System.out.println("sent: " + c.negate().toFriendlyString()); + } }); - wallet.addCoinsSentEventListener(Threading.SAME_THREAD, - (wallet1, tx, prevBalance, newBalance) -> System.out.println("coins sent")); - - wallet.addKeyChainEventListener(Threading.SAME_THREAD, keys -> System.out.println("new key added")); - - wallet.addScriptChangeEventListener(Threading.SAME_THREAD, - (wallet1, scripts, isAddingScripts) -> System.out.println("new script added")); - - wallet.addTransactionConfidenceEventListener(Threading.SAME_THREAD, (wallet1, tx) -> { - System.out.println("-----> confidence changed: " + tx.getHashAsString()); - final TransactionConfidence confidence = tx.getConfidence(); - System.out.println("new block depth: " + confidence.getDepthInBlocks()); - }); + /* + * wallet.addCoinsSentEventListener(Threading.SAME_THREAD, (wallet1, tx, + * prevBalance, newBalance) -> { final Coin c = tx.getValue(wallet1); + * + * if (c.isPositive()) { System.out.println("-----> coins received: " + + * tx.getHashAsString()); System.out.println("received: " + c); } else { + * System.out.println("-----> coins sent: " + tx.getHashAsString()); + * System.out.println("sent: " + c.negate().toFriendlyString()); } + * + * }); + * + * wallet.addKeyChainEventListener(Threading.SAME_THREAD, keys -> + * System.out.println("new key added")); + * + * wallet.addScriptChangeEventListener(Threading.SAME_THREAD, (wallet1, + * scripts, isAddingScripts) -> System.out.println("new script added")); + * + * wallet.addTransactionConfidenceEventListener(Threading.SAME_THREAD, + * (wallet1, tx) -> { System.out.println("-----> confidence changed: " + + * tx.getHashAsString()); final TransactionConfidence confidence = + * tx.getConfidence(); System.out.println("new block depth: " + + * confidence.getDepthInBlocks()); }); + */ // wallet.allowSpendingUnconfirmedTransactions(); handleConsole(kit); @@ -322,44 +374,17 @@ public class App { final OPRETWallet wallet = kit.opretwallet(); final NetworkParameters params = wallet.getNetworkParameters(); - Transaction t = new Transaction(params); - final byte[] sig = sk.sign(revokemsg); + final Transaction t = new Transaction(params); + final byte[] sig = SK.sign(REVOKEMSG); - Script script = new ScriptBuilder().op(OP_RETURN).data(Utils.HEX.decode("ec1d")).data(Utils.HEX.decode("fe")) - .data(pkhash).data(Arrays.copyOfRange(sig, 0, 32)).build(); + final Script script = new ScriptBuilder().op(OP_RETURN).data(Utils.HEX.decode("ec0f")).data(sig) + .data(Arrays.copyOfRange(PKHASH, 0, 12)).build(); t.addOutput(Coin.ZERO, script); - t.addOutput(Transaction.DEFAULT_TX_FEE, wallet.freshAddress(KeyPurpose.CHANGE)); - SendRequest request = SendRequest.forTx(t); + final SendRequest request = SendRequest.forTx(t); request.ensureMinRequiredFee = true; - SendResult sr = null; - + request.shuffleOutputs = false; try { - sr = wallet.sendCoins(request); - } catch (final InsufficientMoneyException e) { - output.println(e.getLocalizedMessage()); - output.flush(); - return false; - } - logger.debug("SendRequest {}", request); - - script = new ScriptBuilder().op(OP_RETURN).data(Utils.HEX.decode("ec1d")).data(Utils.HEX.decode("ff")) - .data(pkhash).data(Arrays.copyOfRange(sig, 32, 64)).build(); - t = new Transaction(params); - - for (final TransactionOutput out : sr.tx.getOutputs()) { - if (out.getValue().compareTo(Transaction.DEFAULT_TX_FEE) == 0) { - logger.debug("Add Output: {} of value {}", out, out.getValue()); - t.addInput(out); - } - } - - t.addOutput(Coin.ZERO, script); - request = SendRequest.forTx(t); - request.ensureMinRequiredFee = true; - sr = null; - - try { - sr = wallet.sendCoins(request); + wallet.sendCoins(request); } catch (final InsufficientMoneyException e) { output.println(e.getLocalizedMessage()); output.flush(); diff --git a/opret-testapp/src/main/java/org/tcpid/opretj/testapp/SigningKey.java b/opret-testapp/src/main/java/org/tcpid/opretj/testapp/SigningKey.java new file mode 100644 index 0000000..ca98503 --- /dev/null +++ b/opret-testapp/src/main/java/org/tcpid/opretj/testapp/SigningKey.java @@ -0,0 +1,94 @@ +/** + * Copyright 2013 Bruno Oliveira, and individual contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.tcpid.opretj.testapp; + +import static org.libsodium.jni.NaCl.sodium; +import static org.libsodium.jni.SodiumConstants.PUBLICKEY_BYTES; +import static org.libsodium.jni.SodiumConstants.SECRETKEY_BYTES; +import static org.libsodium.jni.SodiumConstants.SIGNATURE_BYTES; + +import org.libsodium.jni.crypto.Random; +import org.libsodium.jni.crypto.Util; +import org.libsodium.jni.encoders.Encoder; +import org.libsodium.jni.keys.KeyPair; +import org.libsodium.jni.keys.PrivateKey; + +public class SigningKey { + + private final byte[] seed; + private final byte[] secretKey; + + private final VerifyKey verifyKey; + + public SigningKey() { + this(new Random().randomBytes(SECRETKEY_BYTES)); + } + + public SigningKey(byte[] seed) { + Util.checkLength(seed, SECRETKEY_BYTES); + this.seed = seed; + this.secretKey = Util.zeros(SECRETKEY_BYTES * 2); + final byte[] publicKey = Util.zeros(PUBLICKEY_BYTES); + Util.isValid(sodium().crypto_sign_ed25519_seed_keypair(publicKey, secretKey, seed), + "Failed to generate a key pair"); + + this.verifyKey = new VerifyKey(publicKey); + } + + public SigningKey(String seed, Encoder encoder) { + this(encoder.decode(seed)); + } + + public KeyPair getKeyPair() { + final byte[] sk = Util.zeros(SECRETKEY_BYTES); + sodium().crypto_sign_ed25519_sk_to_curve25519(sk, this.secretKey); + return new KeyPair(sk); + + } + + public PrivateKey getPrivateKey() { + final byte[] sk = Util.zeros(SECRETKEY_BYTES); + sodium().crypto_sign_ed25519_sk_to_curve25519(sk, this.secretKey); + return new PrivateKey(sk); + } + + public VerifyKey getVerifyKey() { + return this.verifyKey; + } + + public byte[] sign(byte[] message) { + byte[] signature = Util.prependZeros(SIGNATURE_BYTES, message); + final int[] bufferLen = new int[1]; + sodium().crypto_sign_ed25519(signature, bufferLen, message, message.length, secretKey); + signature = Util.slice(signature, 0, SIGNATURE_BYTES); + return signature; + } + + public String sign(String message, Encoder encoder) { + final byte[] signature = sign(encoder.decode(message)); + return encoder.encode(signature); + } + + public byte[] toBytes() { + return seed; + } + + @Override + public String toString() { + return Encoder.HEX.encode(seed); + } +} diff --git a/opret-testapp/src/main/java/org/tcpid/opretj/testapp/VerifyKey.java b/opret-testapp/src/main/java/org/tcpid/opretj/testapp/VerifyKey.java new file mode 100644 index 0000000..763108c --- /dev/null +++ b/opret-testapp/src/main/java/org/tcpid/opretj/testapp/VerifyKey.java @@ -0,0 +1,68 @@ +/** + * Copyright 2013 Bruno Oliveira, and individual contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.tcpid.opretj.testapp; + +import static org.libsodium.jni.NaCl.sodium; +import static org.libsodium.jni.SodiumConstants.PUBLICKEY_BYTES; +import static org.libsodium.jni.SodiumConstants.SIGNATURE_BYTES; + +import org.libsodium.jni.crypto.Util; +import org.libsodium.jni.encoders.Encoder; +import org.libsodium.jni.keys.PublicKey; + +public class VerifyKey { + + private final byte[] key; + + public VerifyKey(byte[] key) { + Util.checkLength(key, PUBLICKEY_BYTES); + this.key = key; + } + + public VerifyKey(String key, Encoder encoder) { + this(encoder.decode(key)); + } + + public PublicKey getPublicKey() { + final byte[] pk = Util.zeros(PUBLICKEY_BYTES); + sodium().crypto_sign_ed25519_pk_to_curve25519(pk, this.key); + return new PublicKey(pk); + } + + public byte[] toBytes() { + return key; + } + + @Override + public String toString() { + return Encoder.HEX.encode(key); + } + + public boolean verify(byte[] message, byte[] signature) { + Util.checkLength(signature, SIGNATURE_BYTES); + final byte[] sigAndMsg = Util.merge(signature, message); + final byte[] buffer = Util.zeros(sigAndMsg.length); + final int[] bufferLen = new int[1]; + + return Util.isValid(sodium().crypto_sign_ed25519_open(buffer, bufferLen, sigAndMsg, sigAndMsg.length, key), + "signature was forged or corrupted"); + } + + public boolean verify(String message, String signature, Encoder encoder) { + return verify(encoder.decode(message), encoder.decode(signature)); + } +} diff --git a/opretj/src/main/java/org/tcpid/opretj/OPRETECParser.java b/opretj/src/main/java/org/tcpid/opretj/OPRETECParser.java index 3d8760f..ed63827 100644 --- a/opretj/src/main/java/org/tcpid/opretj/OPRETECParser.java +++ b/opretj/src/main/java/org/tcpid/opretj/OPRETECParser.java @@ -19,7 +19,7 @@ import com.google.common.primitives.Bytes; public class OPRETECParser extends OPRETBaseHandler { private static final Logger logger = LoggerFactory.getLogger(OPRETECParser.class); - private static final List OPRET_MAGIC = Bytes.asList(Utils.HEX.decode("ec1d")); + private static final List OPRET_MAGIC = Bytes.asList(Utils.HEX.decode("ec0f")); protected final Map merkleHashMap = new HashMap<>(); protected final Map transHashMap = new HashMap<>(); private final CopyOnWriteArrayList> opReturnChangeListeners = new CopyOnWriteArrayList<>(); @@ -31,59 +31,43 @@ public class OPRETECParser extends OPRETBaseHandler { */ public void addOPRETECRevokeEventListener(final OPRETECEventListener listener) { // This is thread safe, so we don't need to take the lock. - opReturnChangeListeners - .add(new ListenerRegistration(listener, Threading.SAME_THREAD)); + opReturnChangeListeners.add(new ListenerRegistration(listener, Threading.SAME_THREAD)); } - private boolean checkData(final OPRETTransaction t1, final OPRETTransaction t2) { - final List> opret_data = new ArrayList<>(t1.opretData); - opret_data.addAll(t2.opretData); + private boolean checkData(final OPRETTransaction t) { + final List> opret_data = new ArrayList<>(t.opretData); logger.debug("checking {}", opret_data); + if (opret_data.size() != 3) { + return false; + } + List chunk; chunk = opret_data.get(0); if (!chunk.equals(OPRET_MAGIC)) { - logger.debug("0: != OPRET_MAGIC"); + logger.debug("chunk 0: != OPRET_MAGIC"); return false; } chunk = opret_data.get(1); - if (chunk.size() != 1) { - logger.debug("1: size != 1"); + if ((chunk.size() != 64)) { + logger.debug("chunk 1 size != 64, but {}", chunk.size()); return false; } - if (chunk.get(0) == (byte) 0xFE) { - if (opret_data.size() != 8) { - logger.debug("FE: size != 8"); - return false; - } - chunk = opret_data.get(4); - if (!chunk.equals(OPRET_MAGIC)) { - logger.debug("FE 4 != OPRET_MAGIC"); - return false; - } - if (!opret_data.get(2).equals(opret_data.get(6))) { - logger.debug("FE 2 != 6"); - return false; - } - chunk = opret_data.get(5); - if ((chunk.size() != 1) || (chunk.get(0) != (byte) 0xFF)) { - logger.debug("FE 5 size!=1 or != FF"); - return false; - } - - return handleRevoke(t1, t2); - } else { - logger.debug("1: != 0xFE"); + chunk = opret_data.get(2); + if ((chunk.size() != 12)) { + logger.debug("chunk 2 size!= 12 but {} ", chunk.size()); + return false; } - return false; + return handleRevoke(t); + } - private boolean handleRevoke(final OPRETTransaction t1, final OPRETTransaction t2) { - final byte[] pkhash = Bytes.toArray(t1.opretData.get(2)); - final byte[] sig = Bytes.concat(Bytes.toArray(t1.opretData.get(3)), Bytes.toArray(t2.opretData.get(3))); + private boolean handleRevoke(final OPRETTransaction t) { + final byte[] pkhash = Bytes.toArray(t.opretData.get(2)); + final byte[] sig = Bytes.toArray(t.opretData.get(1)); logger.debug("REVOKE PK {} - SIG {}", Utils.HEX.encode(pkhash), Utils.HEX.encode(sig)); queueOnOPRETRevoke(pkhash, sig); @@ -93,18 +77,7 @@ public class OPRETECParser extends OPRETBaseHandler { @Override public void pushData(final Sha256Hash blockHash, final Sha256Hash txHash, final Set txPrevHash, final List> opret_data) { - final OPRETTransaction optrans = new OPRETTransaction(blockHash, txHash, txPrevHash, opret_data); - logger.debug("pushData: {}", optrans); - for (final Sha256Hash t : txPrevHash) { - if (transHashMap.containsKey(t)) { - final OPRETTransaction opprev = transHashMap.get(t); - if (checkData(opprev, optrans)) { - transHashMap.remove(t); - return; - } - } - } - transHashMap.put(txHash, optrans); + checkData(new OPRETTransaction(blockHash, txHash, opret_data)); } @Override diff --git a/opretj/src/main/java/org/tcpid/opretj/OPRETTransaction.java b/opretj/src/main/java/org/tcpid/opretj/OPRETTransaction.java index 56d2ba5..f833a0e 100644 --- a/opretj/src/main/java/org/tcpid/opretj/OPRETTransaction.java +++ b/opretj/src/main/java/org/tcpid/opretj/OPRETTransaction.java @@ -2,7 +2,6 @@ package org.tcpid.opretj; import java.io.Serializable; import java.util.List; -import java.util.Set; import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.Utils; @@ -16,14 +15,11 @@ public class OPRETTransaction implements Serializable { private static final long serialVersionUID = 4234625243756902517L; public final Sha256Hash blockHash; public final Sha256Hash txHash; - public final Set txPrevHash; public final List> opretData; - public OPRETTransaction(final Sha256Hash blockHash, final Sha256Hash txHash, final Set txPrevHash, - final List> opret_data) { + public OPRETTransaction(final Sha256Hash blockHash, final Sha256Hash txHash, final List> opret_data) { this.blockHash = blockHash; this.txHash = txHash; - this.txPrevHash = txPrevHash; this.opretData = opret_data; } @@ -32,13 +28,6 @@ public class OPRETTransaction implements Serializable { final StringBuilder buf = new StringBuilder(); buf.append("Received in Block: ").append(blockHash).append("\n"); buf.append("TX: ").append(txHash).append("\n"); - buf.append("TxPrev: "); - - for (final Sha256Hash d : txPrevHash) { - buf.append(d.toString()); - buf.append(" "); - } - buf.append("\n"); buf.append("Data: "); for (final List d : opretData) { buf.append(Utils.HEX.encode(Bytes.toArray(d)));