move special EC parser and key handling to testapp

This commit is contained in:
Harald Hoyer 2016-09-14 10:15:47 +02:00
parent 6b50ca4921
commit 765b452f7d
16 changed files with 149 additions and 203 deletions

View file

@ -0,0 +1,18 @@
package org.tcpid.key;
import static org.libsodium.jni.NaCl.sodium;
import org.libsodium.jni.Sodium;
import org.libsodium.jni.crypto.Util;
public class HMACSHA512256 {
public static final int HMACSHA512256_BYTES = sodium().crypto_auth_hmacsha512256_bytes();
public static final int HMACSHA512256_KEYBYTES = sodium().crypto_auth_hmacsha512256_keybytes();
public static byte[] of(final byte[] key, final byte[] msg) {
final byte[] hash = Util.zeros(HMACSHA512256_BYTES);
final byte[] hashkey = Util.prependZeros(HMACSHA512256_KEYBYTES, key);
Sodium.crypto_auth_hmacsha512256(hash, msg, msg.length, hashkey);
return hash;
}
}

View file

@ -0,0 +1,63 @@
package org.tcpid.key;
import java.util.ArrayList;
import org.libsodium.jni.crypto.Hash;
import org.libsodium.jni.encoders.Encoder;
import com.google.common.primitives.Longs;
public class MasterSigningKey extends SigningKey {
public static final Hash HASH = new Hash();
private MasterSigningKey subkey;
private Long subkeyindex;
private final ArrayList<Long> keyindex;
public MasterSigningKey(final byte[] key) {
super(key);
subkey = null;
subkeyindex = 0L;
this.keyindex = new ArrayList<>();
}
public MasterSigningKey(final byte[] key, final ArrayList<Long> keyindex) {
super(key);
subkey = null;
subkeyindex = 0L;
this.keyindex = new ArrayList<>(keyindex);
}
public MasterVerifyKey getMasterVerifyKey() {
return new MasterVerifyKey(this.getVerifyKey().toBytes());
}
public MasterSigningKey getNextValidSubKey(final Long offset) {
return getSubKey(subkeyindex + offset);
}
public MasterSigningKey getSubKey(final Long offset) {
final byte[] ob = Longs.toByteArray(offset);
final byte[] newseed = HMACSHA512256.of(seed, ob);
final ArrayList<Long> ki = new ArrayList<>(this.keyindex);
ki.add(offset);
return new MasterSigningKey(newseed, ki);
}
public MasterSigningKey getValidSubKey() {
if (subkey == null) {
subkey = getSubKey(subkeyindex);
}
return subkey;
}
public void revokeSubKey() {
subkey.setRevoked(true);
subkeyindex++;
subkey = null;
}
@Override
public String toString() {
return "Index: " + this.keyindex.toString() + " " + Encoder.HEX.encode(seed);
}
}

View file

@ -0,0 +1,50 @@
package org.tcpid.key;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import org.tcpid.opretj.OPRETTransaction;
public class MasterVerifyKey extends VerifyKey {
private final LinkedList<MasterVerifyKey> subkeys = new LinkedList<>();
public MasterVerifyKey(final byte[] key) {
super(key);
}
public void clearSubKeys() {
subkeys.clear();
}
public MasterVerifyKey getValidSubKey() {
return subkeys.getFirst();
}
public void revokeSubKey(final MasterVerifyKey key) {
final int i = subkeys.indexOf(key);
if (i == -1) {
throw new NoSuchElementException("No such subkey");
}
subkeys.get(i).setRevoked(true);
subkeys.remove(i);
}
public void setFirstValidSubKey(final MasterVerifyKey key, final OPRETTransaction t1, final OPRETTransaction t2) {
if (!subkeys.isEmpty()) {
throw new IndexOutOfBoundsException("Subkey list is not empty");
}
subkeys.addLast(key);
}
public void setNextValidSubKey(final MasterVerifyKey after, final MasterVerifyKey key) {
final VerifyKey l = subkeys.getLast();
if (!l.equals(after)) {
throw new NoSuchElementException("No such after key, or not last in list");
}
subkeys.addLast(key);
}
}

View file

@ -0,0 +1,125 @@
/**
* 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.key;
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.Sodium;
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 implements Comparable<SigningKey> {
protected final byte[] seed;
private final byte[] secretKey;
private final VerifyKey verifyKey;
private boolean revoked;
public SigningKey() {
this(new Random().randomBytes(SECRETKEY_BYTES));
}
public SigningKey(final byte[] seed) {
Util.checkLength(seed, SECRETKEY_BYTES);
this.seed = seed.clone();
this.secretKey = Util.zeros(SECRETKEY_BYTES * 2);
final byte[] publicKey = Util.zeros(PUBLICKEY_BYTES);
sodium();
Util.isValid(Sodium.crypto_sign_ed25519_seed_keypair(publicKey, secretKey, seed),
"Failed to generate a key pair");
this.verifyKey = new VerifyKey(publicKey);
}
public SigningKey(final String seed, final Encoder encoder) {
this(encoder.decode(seed));
}
@Override
public int compareTo(final SigningKey other) {
for (int i = SECRETKEY_BYTES - 1; i >= 0; i--) {
final int thisByte = this.seed[i] & 0xff;
final int otherByte = other.seed[i] & 0xff;
if (thisByte > otherByte) {
return 1;
}
if (thisByte < otherByte) {
return -1;
}
}
return 0;
}
public KeyPair getKeyPair() {
final byte[] sk = Util.zeros(SECRETKEY_BYTES);
sodium();
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();
Sodium.crypto_sign_ed25519_sk_to_curve25519(sk, this.secretKey);
return new PrivateKey(sk);
}
public VerifyKey getVerifyKey() {
return this.verifyKey;
}
public boolean isRevoked() {
return revoked;
}
public void setRevoked(final boolean revoked) {
if (this.revoked != true) {
this.revoked = revoked;
}
}
public byte[] sign(final byte[] message) {
byte[] signature = Util.prependZeros(SIGNATURE_BYTES, message);
final int[] bufferLen = new int[1];
sodium();
Sodium.crypto_sign_ed25519(signature, bufferLen, message, message.length, secretKey);
signature = Util.slice(signature, 0, SIGNATURE_BYTES);
return signature;
}
public String sign(final String message, final 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);
}
}

View file

@ -0,0 +1,135 @@
/**
* 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.key;
import static org.libsodium.jni.NaCl.sodium;
import static org.libsodium.jni.SodiumConstants.PUBLICKEY_BYTES;
import static org.libsodium.jni.SodiumConstants.SIGNATURE_BYTES;
import java.util.Arrays;
import org.libsodium.jni.Sodium;
import org.libsodium.jni.crypto.Hash;
import org.libsodium.jni.crypto.Util;
import org.libsodium.jni.encoders.Encoder;
import org.libsodium.jni.keys.PublicKey;
public class VerifyKey implements Comparable<VerifyKey> {
public static final Hash HASH = new Hash();
private final byte[] key;
private final byte[] hash;
private final byte[] shortHash;
private boolean revoked;
private MasterVerifyKey masterkey;
public VerifyKey(final byte[] key) {
Util.checkLength(key, PUBLICKEY_BYTES);
this.key = key;
this.hash = HASH.sha256(key);
this.shortHash = Arrays.copyOfRange(hash, 0, 12);
this.revoked = false;
}
public VerifyKey(final String key, final Encoder encoder) {
this(encoder.decode(key));
}
@Override
public int compareTo(final VerifyKey other) {
for (int i = PUBLICKEY_BYTES - 1; i >= 0; i--) {
final int thisByte = this.key[i] & 0xff;
final int otherByte = other.key[i] & 0xff;
if (thisByte > otherByte) {
return 1;
}
if (thisByte < otherByte) {
return -1;
}
}
return 0;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if ((o == null) || (getClass() != o.getClass())) {
return false;
}
return Arrays.equals(key, ((VerifyKey) o).key);
}
public MasterVerifyKey getMasterkey() {
return masterkey;
}
public PublicKey getPublicKey() {
final byte[] pk = Util.zeros(PUBLICKEY_BYTES);
sodium();
Sodium.crypto_sign_ed25519_pk_to_curve25519(pk, this.key);
return new PublicKey(pk);
}
public byte[] getShortHash() {
return this.shortHash;
}
public boolean isRevoked() {
return revoked;
}
public void setMasterkey(final MasterVerifyKey masterkey) {
this.masterkey = masterkey;
}
public void setRevoked(final boolean revoked) {
if (this.revoked != true) {
this.revoked = revoked;
}
}
public byte[] toBytes() {
return key;
}
public byte[] toHash() {
return this.hash;
}
@Override
public String toString() {
return Encoder.HEX.encode(key);
}
public boolean verify(final byte[] message, final 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];
sodium();
return Util.isValid(Sodium.crypto_sign_ed25519_open(buffer, bufferLen, sigAndMsg, sigAndMsg.length, key),
"signature was forged or corrupted");
}
public boolean verify(final String message, final String signature, final Encoder encoder) {
return verify(encoder.decode(message), encoder.decode(signature));
}
}

View file

@ -22,7 +22,6 @@ import org.libsodium.jni.crypto.Hash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tcpid.key.MasterSigningKey;
import org.tcpid.opretj.OPRETECParser;
import org.tcpid.opretj.OPRETWallet;
import org.tcpid.opretj.OPRETWalletAppKit;

View file

@ -0,0 +1,7 @@
package org.tcpid.opretj.testapp;
import org.tcpid.key.MasterVerifyKey;
public interface OPRETECEventListener {
void onOPRETRevoke(MasterVerifyKey key);
}

View file

@ -0,0 +1,429 @@
package org.tcpid.opretj.testapp;
import static org.bitcoinj.script.ScriptOpCodes.OP_RETURN;
import static org.libsodium.jni.NaCl.sodium;
import static org.libsodium.jni.SodiumConstants.NONCE_BYTES;
import static org.libsodium.jni.SodiumConstants.SECRETKEY_BYTES;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import org.bitcoinj.core.PartialMerkleTree;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.Utils;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;
import org.bitcoinj.utils.ListenerRegistration;
import org.bitcoinj.utils.Threading;
import org.libsodium.jni.Sodium;
import org.libsodium.jni.crypto.Hash;
import org.libsodium.jni.crypto.Util;
import org.libsodium.jni.encoders.Encoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tcpid.key.HMACSHA512256;
import org.tcpid.key.MasterSigningKey;
import org.tcpid.key.MasterVerifyKey;
import org.tcpid.key.SigningKey;
import org.tcpid.key.VerifyKey;
import org.tcpid.opretj.OPRETBaseHandler;
import org.tcpid.opretj.OPRETTransaction;
import com.google.common.primitives.Bytes;
public class OPRETECParser extends OPRETBaseHandler {
private static final Logger logger = LoggerFactory.getLogger(OPRETECParser.class);
public static final Hash HASH = new Hash();
private static final List<Byte> OPRET_MAGIC_EC1C = Bytes.asList(Utils.HEX.decode("ec1c"));
private static final List<Byte> OPRET_MAGIC_EC1D = Bytes.asList(Utils.HEX.decode("ec1d"));
private static final List<Byte> OPRET_MAGIC_ECA1 = Bytes.asList(Utils.HEX.decode("eca1"));
private static final List<Byte> OPRET_MAGIC_ECA2 = Bytes.asList(Utils.HEX.decode("eca2"));
private static final List<Byte> OPRET_MAGIC_ECA3 = Bytes.asList(Utils.HEX.decode("eca3"));
private static final List<Byte> OPRET_MAGIC_ECA4 = Bytes.asList(Utils.HEX.decode("eca4"));
private static final List<Byte> OPRET_MAGIC_EC51 = Bytes.asList(Utils.HEX.decode("ec51"));
private static final List<Byte> OPRET_MAGIC_EC52 = Bytes.asList(Utils.HEX.decode("ec52"));
private static final List<Byte> OPRET_MAGIC_EC0F = Bytes.asList(Utils.HEX.decode("ec0f"));
public static boolean checkKeyforRevoke(final VerifyKey k, final byte[] sig) {
logger.debug("CHECKING REVOKE PKHASH {} - SIG {}", Utils.HEX.encode(k.toHash()), Utils.HEX.encode(sig));
final byte[] revokemsg = Bytes.concat("Revoke ".getBytes(), k.toHash());
logger.debug("Using VerifyKey {}", k);
if (k.verify(revokemsg, sig)) {
logger.debug("REVOKED VerifyKey {}", k);
return true;
} else {
logger.debug("SIGNATURE does not match!");
return false;
}
}
public static Script getRevokeScript(final SigningKey key) {
final byte[] revokemsg = Bytes.concat("Revoke ".getBytes(), key.getVerifyKey().toHash());
final byte[] sig = key.sign(revokemsg);
final Script script = new ScriptBuilder().op(OP_RETURN).data(Utils.HEX.decode("ec0f")).data(sig)
.data(key.getVerifyKey().getShortHash()).build();
return script;
}
protected final Map<Sha256Hash, PartialMerkleTree> merkleHashMap = Collections.synchronizedMap(new HashMap<>());
protected final Map<Sha256Hash, OPRETTransaction> transHashMap = Collections.synchronizedMap(new HashMap<>());
protected final Map<List<Byte>, List<OPRETTransaction>> transA1HashMap = Collections
.synchronizedMap(new HashMap<>());
protected final Map<List<Byte>, List<OPRETTransaction>> transA2HashMap = Collections
.synchronizedMap(new HashMap<>());
protected final Map<List<Byte>, List<OPRETTransaction>> transA3HashMap = Collections
.synchronizedMap(new HashMap<>());
protected final Map<List<Byte>, List<OPRETTransaction>> transA4HashMap = Collections
.synchronizedMap(new HashMap<>());
protected final Map<List<Byte>, List<OPRETTransaction>> trans51HashMap = Collections
.synchronizedMap(new HashMap<>());
protected final Map<List<Byte>, List<OPRETTransaction>> trans52HashMap = Collections
.synchronizedMap(new HashMap<>());
protected final Map<List<Byte>, List<MasterVerifyKey>> verifyKeys = Collections.synchronizedMap(new HashMap<>());
private final CopyOnWriteArrayList<ListenerRegistration<OPRETECEventListener>> opReturnChangeListeners = new CopyOnWriteArrayList<>();
/**
* Adds an event listener object. Methods on this object are called when
* scripts watched by this wallet change. The listener is executed by the
* given executor.
*/
public void addOPRETECRevokeEventListener(final OPRETECEventListener listener) {
// This is thread safe, so we don't need to take the lock.
opReturnChangeListeners.add(new ListenerRegistration<OPRETECEventListener>(listener, Threading.SAME_THREAD));
}
public void addVerifyKey(final MasterVerifyKey key, final long earliestTime) {
final List<Byte> hash = Bytes.asList(key.getShortHash());
if (!verifyKeys.containsKey(hash)) {
verifyKeys.put(hash, new ArrayList<MasterVerifyKey>());
}
verifyKeys.get(hash).add(key);
logger.debug("Adding pkhash {}", key.getShortHash());
addOPRET(key.getShortHash(), earliestTime);
}
public boolean cryptoSelfTest() {
if (NONCE_BYTES > HMACSHA512256.HMACSHA512256_BYTES) {
logger.error("NONCE_BYTES > HMACSHA512256.HMACSHA512256_BYTES: {} > {}", NONCE_BYTES,
HMACSHA512256.HMACSHA512256_BYTES);
return false;
}
if (SECRETKEY_BYTES != HMACSHA512256.HMACSHA512256_BYTES) {
logger.error("SECRETKEY_BYTES != HMACSHA512256.HMACSHA512256_BYTES: {} > {}", SECRETKEY_BYTES,
HMACSHA512256.HMACSHA512256_BYTES);
return false;
}
final MasterSigningKey msk = new MasterSigningKey(HASH.sha256("TESTSEED".getBytes()));
if (!Arrays.equals(Utils.HEX.decode("4071b2b3db7cc7aecd0b23608e96f44f08463ea0ee0a0c12f5fa21ff449deb55"),
msk.toBytes())) {
logger.error("MasterSigningKey(HASH.sha256('TESTSEED'.getBytes())) test failed");
return false;
}
final MasterSigningKey subkey = msk.getSubKey(1L).getSubKey(2L).getSubKey(3L).getSubKey(4L);
if (!Arrays.equals(Utils.HEX.decode("00cb0c8748318d27eab65159a2261c028d764c1154fc302b9b046aa2bbefab27"),
subkey.toBytes())) {
logger.error("MasterSigningKey subkey derivation failed");
return false;
}
final BigInteger biMSK = new BigInteger(1, msk.toBytes());
BigInteger biSub = new BigInteger(1, subkey.toBytes());
final BigInteger pow2_256 = new BigInteger("10000000000000000000000000000000000000000000000000000000000000000",
16);
final BigInteger biDiff = biSub.subtract(biMSK).mod(pow2_256);
logger.debug("{} = {}", Utils.HEX.encode(msk.toBytes()), biMSK.toString(16));
logger.debug("{} - {} = {}", Utils.HEX.encode(msk.toBytes()), Utils.HEX.encode(subkey.toBytes()),
Utils.HEX.encode(biDiff.toByteArray()));
biSub = biMSK.add(biDiff).mod(pow2_256);
final byte[] bisubb = biSub.toByteArray();
logger.debug("{}", Utils.HEX.encode(Util.prependZeros(32 - bisubb.length, bisubb)));
if (!Arrays.equals(bisubb, subkey.toBytes())) {
logger.error("MasterSigningKey subkey difference calculation failed");
return false;
}
return true;
}
private boolean handleAnnounce(final OPRETTransaction selfTx,
final Map<List<Byte>, List<OPRETTransaction>> selfTransHashMap,
final Map<List<Byte>, List<OPRETTransaction>> otherTransHashMap, final boolean isT1) {
final byte[] selfData = Bytes.toArray(selfTx.opretData.get(1));
if (((selfData.length < 48) || (selfData.length > 64))) {
logger.debug("invalid chunk1 size = {}", selfData.length);
return false;
}
final List<Byte> pkhash = selfTx.opretData.get(2);
if ((pkhash.size() != 12)) {
logger.debug("chunk 2 size != 12 but {} ", pkhash.size());
return false;
}
if (!verifyKeys.containsKey(pkhash)) {
return false;
}
if (otherTransHashMap.containsKey(pkhash)) {
for (final OPRETTransaction otherTx : otherTransHashMap.get(pkhash)) {
final byte[] otherData = Bytes.toArray(otherTx.opretData.get(1));
final byte[] cipher = isT1
? Bytes.concat(Arrays.copyOfRange(selfData, 0, 48), Arrays.copyOfRange(otherData, 0, 48))
: Bytes.concat(Arrays.copyOfRange(otherData, 0, 48), Arrays.copyOfRange(selfData, 0, 48));
final BigInteger selfNonce = (selfData.length == 48) ? BigInteger.ZERO
: new BigInteger(1, Arrays.copyOfRange(selfData, 48, selfData.length));
final BigInteger otherNonce = (otherData.length == 48) ? BigInteger.ZERO
: new BigInteger(1, Arrays.copyOfRange(otherData, 48, otherData.length));
final BigInteger nonce = isT1 ? selfNonce.shiftLeft(16 * 8).or(otherNonce)
: otherNonce.shiftLeft(16 * 8).or(selfNonce);
byte[] noncebytes = Util.prependZeros(32, nonce.toByteArray());
noncebytes = Arrays.copyOfRange(noncebytes, noncebytes.length - 32, noncebytes.length);
for (final MasterVerifyKey k : verifyKeys.get(pkhash)) {
byte[] sharedkey, xornonce;
sharedkey = HASH.sha256(HASH.sha256(Bytes.concat(k.toBytes(), noncebytes)));
xornonce = Arrays.copyOfRange(HASH.sha256(Bytes.concat(sharedkey, noncebytes)), 0, 24);
logger.debug("checking key {}", Encoder.HEX.encode(k.toBytes()));
logger.debug("noncebytes {}", Encoder.HEX.encode(noncebytes));
logger.debug("noncebytes len {}", noncebytes.length);
logger.debug("xornonce {}", Encoder.HEX.encode(xornonce));
logger.debug("sharedkey {}", Encoder.HEX.encode(sharedkey));
sodium();
final byte[] msg = Util.zeros(96);
Sodium.crypto_stream_xsalsa20_xor(msg, cipher, 96, xornonce, sharedkey);
final byte[] vk = Arrays.copyOfRange(msg, 0, 32);
final byte[] sig = Arrays.copyOfRange(msg, 32, 96);
try {
logger.debug("Checking sig {} with key {}", Encoder.HEX.encode(sig), Encoder.HEX.encode(vk));
k.verify(vk, sig);
} catch (final RuntimeException e) {
logger.debug("sig does not match");
continue;
}
logger.debug("sig matches");
k.setFirstValidSubKey(new MasterVerifyKey(vk), selfTx, otherTx);
otherTransHashMap.get(pkhash).remove(otherTx);
if (otherTransHashMap.get(pkhash).isEmpty()) {
otherTransHashMap.remove(pkhash);
}
return true;
}
}
}
// no matching transaction found, save for later
if (!selfTransHashMap.containsKey(pkhash)) {
selfTransHashMap.put(pkhash, new ArrayList<OPRETTransaction>());
}
selfTransHashMap.get(pkhash).add(selfTx);
return false;
}
private boolean handleEC0F(final OPRETTransaction t) {
final byte[] sig = Bytes.toArray(t.opretData.get(1));
if ((sig.length != 64)) {
logger.debug("chunk 1 size != 64, but {}", sig.length);
return false;
}
final List<Byte> pkhash = t.opretData.get(2);
if ((pkhash.size() != 12)) {
logger.debug("chunk 2 size!= 12 but {} ", pkhash.size());
return false;
}
if (!verifyKeys.containsKey(pkhash)) {
return false;
}
for (final MasterVerifyKey k : verifyKeys.get(pkhash)) {
if (checkKeyforRevoke(k, sig)) {
if (k.isRevoked()) {
logger.debug("Duplicate REVOKE PK {} - SIG {}", Utils.HEX.encode(k.getShortHash()),
Utils.HEX.encode(sig));
} else {
k.setRevoked(true);
logger.debug("REVOKE PK {} - SIG {}", Utils.HEX.encode(k.getShortHash()), Utils.HEX.encode(sig));
}
queueOnOPRETRevoke(k);
return true;
}
}
return false;
}
private boolean handleEC1C(final OPRETTransaction t) {
// TODO Auto-generated method stub
return false;
}
private boolean handleEC1D(final OPRETTransaction t) {
final byte[] sig = Bytes.toArray(t.opretData.get(1));
if ((sig.length != 64)) {
logger.debug("chunk 1 size != 64, but {}", sig.length);
return false;
}
final List<Byte> pkhash = t.opretData.get(2);
if ((pkhash.size() != 12)) {
logger.debug("chunk 2 size!= 12 but {} ", pkhash.size());
return false;
}
if (!verifyKeys.containsKey(pkhash)) {
return false;
}
for (final MasterVerifyKey k : verifyKeys.get(pkhash)) {
if (checkKeyforRevoke(k, sig)) {
if (k.isRevoked()) {
logger.debug("Duplicate REVOKE PK {} - SIG {}", Utils.HEX.encode(k.getShortHash()),
Utils.HEX.encode(sig));
} else {
k.setRevoked(true);
logger.debug("REVOKE PK {} - SIG {}", Utils.HEX.encode(k.getShortHash()), Utils.HEX.encode(sig));
}
queueOnOPRETId(k);
return true;
}
}
return false;
}
private boolean handleEC51(final OPRETTransaction t) {
// TODO Auto-generated method stub
return false;
}
private boolean handleEC52(final OPRETTransaction t) {
// TODO Auto-generated method stub
return false;
}
private boolean handleECA1(final OPRETTransaction t1) {
logger.debug("handleECA1");
return handleAnnounce(t1, transA1HashMap, transA2HashMap, true);
}
private boolean handleECA2(final OPRETTransaction t2) {
logger.debug("handleECA2");
return handleAnnounce(t2, transA2HashMap, transA1HashMap, false);
}
private boolean handleECA3(final OPRETTransaction t) {
// TODO Auto-generated method stub
return false;
}
private boolean handleECA4(final OPRETTransaction t) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean pushTransaction(final OPRETTransaction t) {
logger.debug("checking {}", t.opretData);
if ((t.opretData.size() != 2) && (t.opretData.size() != 3) && (t.opretData.size() != 4)) {
return false;
}
final List<Byte> chunk = t.opretData.get(0);
if (chunk.equals(OPRET_MAGIC_EC0F)) {
return handleEC0F(t);
}
if (chunk.equals(OPRET_MAGIC_EC1C)) {
return handleEC1C(t);
}
if (chunk.equals(OPRET_MAGIC_EC1D)) {
return handleEC1D(t);
}
if (chunk.equals(OPRET_MAGIC_ECA1)) {
return handleECA1(t);
}
if (chunk.equals(OPRET_MAGIC_ECA2)) {
return handleECA2(t);
}
if (chunk.equals(OPRET_MAGIC_ECA3)) {
return handleECA3(t);
}
if (chunk.equals(OPRET_MAGIC_ECA4)) {
return handleECA4(t);
}
if (chunk.equals(OPRET_MAGIC_EC51)) {
return handleEC51(t);
}
if (chunk.equals(OPRET_MAGIC_EC52)) {
return handleEC52(t);
}
return false;
}
private void queueOnOPRETId(final MasterVerifyKey k) {
// TODO Auto-generated method stub
}
protected void queueOnOPRETRevoke(final MasterVerifyKey key) {
for (final ListenerRegistration<OPRETECEventListener> registration : opReturnChangeListeners) {
registration.executor.execute(() -> registration.listener.onOPRETRevoke(key));
}
}
/**
* Removes the given event listener object. Returns true if the listener was
* removed, false if that listener was never added.
*/
public boolean removeOPRETECRevokeEventListener(final OPRETECEventListener listener) {
return ListenerRegistration.removeFromList(listener, opReturnChangeListeners);
}
public void removeVerifyKey(final MasterVerifyKey key) {
final List<Byte> hash = Bytes.asList(key.getShortHash());
if (!verifyKeys.containsKey(hash)) {
return;
}
verifyKeys.get(hash).remove(key);
removeOPRET(key.getShortHash());
}
}