add ECA3 and ECA4
This commit is contained in:
parent
f68d85cea0
commit
1bd005fb5e
|
@ -60,6 +60,7 @@ A MK is stored along with the key birthday, which is the date of the first appea
|
||||||
### MVK announce subkey VK 0xECA[1,2] - A-nnounce
|
### MVK announce subkey VK 0xECA[1,2] - A-nnounce
|
||||||
|
|
||||||
nonce[0:32] = nonce[0:16] | nonce[16:32]
|
nonce[0:32] = nonce[0:16] | nonce[16:32]
|
||||||
|
|
||||||
data chunks are prepended with zeros, if its length is smaller than 16.
|
data chunks are prepended with zeros, if its length is smaller than 16.
|
||||||
E.g.
|
E.g.
|
||||||
|
|
||||||
|
@ -74,14 +75,16 @@ If nonce is missing completely, then
|
||||||
is assumed.
|
is assumed.
|
||||||
|
|
||||||
A nonce **must** be used only once. Either only one VK_pub is announced per MVK ever and nonce is missing,
|
A nonce **must** be used only once. Either only one VK_pub is announced per MVK ever and nonce is missing,
|
||||||
or for every MVK announcement, the nonce has to be *unique* or *true random* bytes.
|
or for every MVK announcement, the nonce has to be **unique** or **true random** bytes.
|
||||||
|
|
||||||
|
```
|
||||||
sharedkey = sha256(sha256(MVK_pub | nonce))
|
sharedkey = sha256(sha256(MVK_pub | nonce))
|
||||||
xornonce[24] = sha256(sharedkey | nonce)[0:24]
|
xornonce[24] = sha256(sharedkey | nonce)[0:24]
|
||||||
|
|
||||||
sig[64] = crypto_sign(VK_pub, MKV)
|
sig[64] = crypto_sign(VK_pub, MKV)
|
||||||
msg[96] = VK_pub || sig
|
msg[96] = VK_pub || sig
|
||||||
cipher[96] = crypto_stream_xor(msg, xornonce, sharedkey)
|
cipher[96] = crypto_stream_xor(msg, xornonce, sharedkey)
|
||||||
|
```
|
||||||
|
|
||||||
clients may flush T1, if T2 does not follow in the next 20 blocks
|
clients may flush T1, if T2 does not follow in the next 20 blocks
|
||||||
clients may flush T2, if T1 does not follow in the next 20 blocks
|
clients may flush T2, if T1 does not follow in the next 20 blocks
|
||||||
|
@ -94,12 +97,14 @@ clients may flush T2, if T1 does not follow in the next 20 blocks
|
||||||
| Size | 1 | 3 | 49 | 13 |
|
| Size | 1 | 3 | 49 | 13 |
|
||||||
|
|
||||||
### MVK announce next subkey VK_n+1 0xECA[3,4] - A-nnounce
|
### MVK announce next subkey VK_n+1 0xECA[3,4] - A-nnounce
|
||||||
|
```
|
||||||
sharedkey = sha256(sha256(VK_n_pub))
|
sharedkey = sha256(sha256(VK_n_pub))
|
||||||
nonce[24] = sha256(sharedkey)[0:24]
|
nonce[24] = sha256(sharedkey)[0:24]
|
||||||
|
|
||||||
sig[64] = crypto_sign(VK_n+1_pub, MKV)
|
sig[64] = crypto_sign(VK_n+1_pub, MKV)
|
||||||
msg[96] = VK_n+1_pub || sig
|
msg[96] = VK_n+1_pub || sig
|
||||||
cipher[96] = crypto_stream_xor(msg, nonce, sharedkey)
|
cipher[96] = crypto_stream_xor(msg, nonce, sharedkey)
|
||||||
|
```
|
||||||
|
|
||||||
clients may flush T1, if T2 does not follow in the next 20 blocks
|
clients may flush T1, if T2 does not follow in the next 20 blocks
|
||||||
clients may flush T2, if T1 does not follow in the next 20 blocks
|
clients may flush T2, if T1 does not follow in the next 20 blocks
|
||||||
|
@ -112,8 +117,10 @@ clients may flush T2, if T1 does not follow in the next 20 blocks
|
||||||
| Size | 1 | 3 | 49 | 13 | 13 |
|
| Size | 1 | 3 | 49 | 13 | 13 |
|
||||||
|
|
||||||
### Public Doc or other key OK sign 0xEC5[1,2]
|
### Public Doc or other key OK sign 0xEC5[1,2]
|
||||||
|
```
|
||||||
sign[64] = Sign_Key('Sign ' || sha256(Doc/OK))
|
sign[64] = Sign_Key('Sign ' || sha256(Doc/OK))
|
||||||
data = optional data (max 2*19 bytes)
|
data = optional data (max 2*19 bytes)
|
||||||
|
```
|
||||||
|
|
||||||
clients may flush T1, if T2 does not follow in the next 20 blocks
|
clients may flush T1, if T2 does not follow in the next 20 blocks
|
||||||
clients may flush T2, if T1 does not follow in the next 20 blocks
|
clients may flush T2, if T1 does not follow in the next 20 blocks
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
package org.tcpid.key;
|
package org.tcpid.key;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
import org.tcpid.opretj.OPRETTransaction;
|
import org.tcpid.opretj.OPRETTransaction;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
|
|
||||||
public class MasterVerifyKey extends VerifyKey {
|
public class MasterVerifyKey extends VerifyKey {
|
||||||
private final LinkedList<MasterVerifyKey> subkeys = new LinkedList<>();
|
private final LinkedList<MasterVerifyKey> subkeys = new LinkedList<>();
|
||||||
|
|
||||||
|
@ -16,6 +20,15 @@ public class MasterVerifyKey extends VerifyKey {
|
||||||
subkeys.clear();
|
subkeys.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MasterVerifyKey getSubKeybyHash(List<Byte> subpkhash) {
|
||||||
|
for (final MasterVerifyKey k : subkeys) {
|
||||||
|
if (Arrays.equals(k.getShortHash(), Bytes.toArray(subpkhash))) {
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public MasterVerifyKey getValidSubKey() {
|
public MasterVerifyKey getValidSubKey() {
|
||||||
return subkeys.getFirst();
|
return subkeys.getFirst();
|
||||||
}
|
}
|
||||||
|
@ -39,8 +52,9 @@ public class MasterVerifyKey extends VerifyKey {
|
||||||
subkeys.addLast(key);
|
subkeys.addLast(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNextValidSubKey(final MasterVerifyKey after, final MasterVerifyKey key) {
|
public void setNextValidSubKey(final MasterVerifyKey after, final MasterVerifyKey key, OPRETTransaction t1,
|
||||||
final VerifyKey l = subkeys.getLast();
|
OPRETTransaction t2) {
|
||||||
|
final MasterVerifyKey l = subkeys.getLast();
|
||||||
if (!l.equals(after)) {
|
if (!l.equals(after)) {
|
||||||
throw new NoSuchElementException("No such after key, or not last in list");
|
throw new NoSuchElementException("No such after key, or not last in list");
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,8 +124,13 @@ public class VerifyKey implements Comparable<VerifyKey> {
|
||||||
final int[] bufferLen = new int[1];
|
final int[] bufferLen = new int[1];
|
||||||
|
|
||||||
sodium();
|
sodium();
|
||||||
return Util.isValid(Sodium.crypto_sign_ed25519_open(buffer, bufferLen, sigAndMsg, sigAndMsg.length, key),
|
try {
|
||||||
"signature was forged or corrupted");
|
Util.isValid(Sodium.crypto_sign_ed25519_open(buffer, bufferLen, sigAndMsg, sigAndMsg.length, key),
|
||||||
|
"signature was forged or corrupted");
|
||||||
|
return true;
|
||||||
|
} catch (final Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean verify(final String message, final String signature, final Encoder encoder) {
|
public boolean verify(final String message, final String signature, final Encoder encoder) {
|
||||||
|
|
|
@ -168,7 +168,7 @@ public class OPRETECParser extends OPRETBaseHandler {
|
||||||
private boolean handleAnnounce(final OPRETTransaction selfTx,
|
private boolean handleAnnounce(final OPRETTransaction selfTx,
|
||||||
final Map<List<Byte>, List<OPRETTransaction>> selfTransHashMap,
|
final Map<List<Byte>, List<OPRETTransaction>> selfTransHashMap,
|
||||||
final Map<List<Byte>, List<OPRETTransaction>> otherTransHashMap, final boolean isT1) {
|
final Map<List<Byte>, List<OPRETTransaction>> otherTransHashMap, final boolean isT1) {
|
||||||
|
logger.debug("handleAnnounce");
|
||||||
final byte[] selfData = Bytes.toArray(selfTx.opretData.get(1));
|
final byte[] selfData = Bytes.toArray(selfTx.opretData.get(1));
|
||||||
if (((selfData.length < 48) || (selfData.length > 64))) {
|
if (((selfData.length < 48) || (selfData.length > 64))) {
|
||||||
logger.debug("invalid chunk1 size = {}", selfData.length);
|
logger.debug("invalid chunk1 size = {}", selfData.length);
|
||||||
|
@ -176,7 +176,7 @@ public class OPRETECParser extends OPRETBaseHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Byte> pkhash = selfTx.opretData.get(2);
|
final List<Byte> pkhash = selfTx.opretData.get(2);
|
||||||
if ((pkhash.size() != 12)) {
|
if (pkhash.size() != 12) {
|
||||||
logger.debug("chunk 2 size != 12 but {} ", pkhash.size());
|
logger.debug("chunk 2 size != 12 but {} ", pkhash.size());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -216,16 +216,16 @@ public class OPRETECParser extends OPRETBaseHandler {
|
||||||
Sodium.crypto_stream_xsalsa20_xor(msg, cipher, 96, xornonce, sharedkey);
|
Sodium.crypto_stream_xsalsa20_xor(msg, cipher, 96, xornonce, sharedkey);
|
||||||
final byte[] vk = Arrays.copyOfRange(msg, 0, 32);
|
final byte[] vk = Arrays.copyOfRange(msg, 0, 32);
|
||||||
final byte[] sig = Arrays.copyOfRange(msg, 32, 96);
|
final byte[] sig = Arrays.copyOfRange(msg, 32, 96);
|
||||||
try {
|
logger.debug("Checking sig {} with key {}", Encoder.HEX.encode(sig), Encoder.HEX.encode(vk));
|
||||||
logger.debug("Checking sig {} with key {}", Encoder.HEX.encode(sig), Encoder.HEX.encode(vk));
|
|
||||||
k.verify(vk, sig);
|
if (!k.verify(vk, sig)) {
|
||||||
} catch (final RuntimeException e) {
|
|
||||||
logger.debug("sig does not match");
|
logger.debug("sig does not match");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("sig matches");
|
logger.debug("sig matches");
|
||||||
|
|
||||||
k.setFirstValidSubKey(new MasterVerifyKey(vk), selfTx, otherTx);
|
k.setFirstValidSubKey(new MasterVerifyKey(vk), isT1 ? selfTx : otherTx, isT1 ? otherTx : selfTx);
|
||||||
otherTransHashMap.get(pkhash).remove(otherTx);
|
otherTransHashMap.get(pkhash).remove(otherTx);
|
||||||
if (otherTransHashMap.get(pkhash).isEmpty()) {
|
if (otherTransHashMap.get(pkhash).isEmpty()) {
|
||||||
otherTransHashMap.remove(pkhash);
|
otherTransHashMap.remove(pkhash);
|
||||||
|
@ -337,13 +337,91 @@ public class OPRETECParser extends OPRETBaseHandler {
|
||||||
return handleAnnounce(t2, transA2HashMap, transA1HashMap, false);
|
return handleAnnounce(t2, transA2HashMap, transA1HashMap, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleECA3(final OPRETTransaction t) {
|
private boolean handleECA3(final OPRETTransaction t1) {
|
||||||
// TODO Auto-generated method stub
|
logger.debug("handleECA3");
|
||||||
return false;
|
return handleNextKey(t1, transA3HashMap, transA4HashMap, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleECA4(final OPRETTransaction t) {
|
private boolean handleECA4(final OPRETTransaction t2) {
|
||||||
// TODO Auto-generated method stub
|
logger.debug("handleECA4");
|
||||||
|
return handleNextKey(t2, transA4HashMap, transA3HashMap, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleNextKey(final OPRETTransaction selfTx,
|
||||||
|
final Map<List<Byte>, List<OPRETTransaction>> selfTransHashMap,
|
||||||
|
final Map<List<Byte>, List<OPRETTransaction>> otherTransHashMap, final boolean isT1) {
|
||||||
|
|
||||||
|
logger.debug("handleNextKey");
|
||||||
|
final byte[] selfData = Bytes.toArray(selfTx.opretData.get(1));
|
||||||
|
if (selfData.length != 48) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Byte> subpkhash = selfTx.opretData.get(3);
|
||||||
|
if (subpkhash.size() != 12) {
|
||||||
|
logger.debug("chunk 2 size != 12 but {} ", subpkhash.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(selfData, otherData) : Bytes.concat(otherData, selfData);
|
||||||
|
|
||||||
|
for (final MasterVerifyKey k : verifyKeys.get(pkhash)) {
|
||||||
|
final MasterVerifyKey vk_n = k.getSubKeybyHash(subpkhash);
|
||||||
|
if (vk_n == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final byte[] sharedkey = HASH.sha256(vk_n.toHash());
|
||||||
|
final byte[] xornonce = Arrays.copyOfRange(HASH.sha256(sharedkey), 0, 24);
|
||||||
|
logger.debug("checking key {}", Encoder.HEX.encode(k.toBytes()));
|
||||||
|
logger.debug("checking subkey {}", Encoder.HEX.encode(vk_n.toBytes()));
|
||||||
|
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);
|
||||||
|
logger.debug("Checking sig {} with key {}", Encoder.HEX.encode(sig), Encoder.HEX.encode(vk));
|
||||||
|
|
||||||
|
if (!k.verify(vk, sig)) {
|
||||||
|
logger.debug("sig does not match");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("sig matches");
|
||||||
|
|
||||||
|
k.setNextValidSubKey(vk_n, new MasterVerifyKey(vk), isT1 ? selfTx : otherTx,
|
||||||
|
isT1 ? otherTx : selfTx);
|
||||||
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,6 +430,7 @@ public class OPRETECParser extends OPRETBaseHandler {
|
||||||
logger.debug("checking {}", t.opretData);
|
logger.debug("checking {}", t.opretData);
|
||||||
|
|
||||||
if ((t.opretData.size() != 2) && (t.opretData.size() != 3) && (t.opretData.size() != 4)) {
|
if ((t.opretData.size() != 2) && (t.opretData.size() != 3) && (t.opretData.size() != 4)) {
|
||||||
|
logger.debug("Wrong chunk count");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
<logger name="org.bitcoinj.core.PeerSocketHandler" level="error" />
|
<logger name="org.bitcoinj.core.PeerSocketHandler" level="error" />
|
||||||
<logger name="org.bitcoinj.net.ConnectionHandler" level="error" />
|
<logger name="org.bitcoinj.net.ConnectionHandler" level="error" />
|
||||||
<logger name="org.tcpid.opret.OPRETECParser" level="debug" />
|
<logger name="org.tcpid.opret.OPRETECParser" level="debug" />
|
||||||
|
<logger name="org.tcpid.opret.TestCrypto" level="debug" />
|
||||||
<!--
|
<!--
|
||||||
<logger name="eckey.OPRETSimpleLogger" level="debug" />
|
<logger name="eckey.OPRETSimpleLogger" level="debug" />
|
||||||
<logger name="eckey.OPRETSimpleParser" level="debug" />
|
<logger name="eckey.OPRETSimpleParser" level="debug" />
|
||||||
|
|
|
@ -30,7 +30,7 @@ public class TestCrypto {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDerive() {
|
public void testDerive() {
|
||||||
|
logger.debug("testDerive");
|
||||||
assertTrue("NONCE_BYTES > HMACSHA512256.HMACSHA512256_BYTES", NONCE_BYTES <= HMACSHA512256.HMACSHA512256_BYTES);
|
assertTrue("NONCE_BYTES > HMACSHA512256.HMACSHA512256_BYTES", NONCE_BYTES <= HMACSHA512256.HMACSHA512256_BYTES);
|
||||||
assertEquals(SECRETKEY_BYTES, HMACSHA512256.HMACSHA512256_BYTES);
|
assertEquals(SECRETKEY_BYTES, HMACSHA512256.HMACSHA512256_BYTES);
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@ public class TestCrypto {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSign() {
|
public void testSign() {
|
||||||
|
logger.debug("testSign");
|
||||||
final MasterSigningKey msk = new MasterSigningKey(HASH.sha256("TESTSEED".getBytes()));
|
final MasterSigningKey msk = new MasterSigningKey(HASH.sha256("TESTSEED".getBytes()));
|
||||||
final MasterVerifyKey vk = msk.getMasterVerifyKey();
|
final MasterVerifyKey vk = msk.getMasterVerifyKey();
|
||||||
final byte[] revokemsg = Bytes.concat("Revoke ".getBytes(), vk.toHash());
|
final byte[] revokemsg = Bytes.concat("Revoke ".getBytes(), vk.toHash());
|
||||||
|
@ -66,6 +67,7 @@ public class TestCrypto {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSignEnc() {
|
public void testSignEnc() {
|
||||||
|
logger.debug("testSignEnc");
|
||||||
final MasterSigningKey msk = new MasterSigningKey(HASH.sha256("TESTSEED".getBytes()));
|
final MasterSigningKey msk = new MasterSigningKey(HASH.sha256("TESTSEED".getBytes()));
|
||||||
final MasterVerifyKey subkey = msk.getSubKey(1L).getMasterVerifyKey();
|
final MasterVerifyKey subkey = msk.getSubKey(1L).getMasterVerifyKey();
|
||||||
final MasterVerifyKey vk = msk.getMasterVerifyKey();
|
final MasterVerifyKey vk = msk.getMasterVerifyKey();
|
||||||
|
@ -97,8 +99,46 @@ public class TestCrypto {
|
||||||
assertArrayEquals(subkey.toBytes(), vkb);
|
assertArrayEquals(subkey.toBytes(), vkb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSignEncNext() {
|
||||||
|
logger.debug("testSignEncNext");
|
||||||
|
|
||||||
|
final MasterSigningKey msk = new MasterSigningKey(HASH.sha256("TESTSEED".getBytes()));
|
||||||
|
final MasterVerifyKey mvk = msk.getMasterVerifyKey();
|
||||||
|
final MasterVerifyKey subkey1 = msk.getSubKey(1L).getMasterVerifyKey();
|
||||||
|
final MasterVerifyKey subkey2 = msk.getSubKey(2L).getMasterVerifyKey();
|
||||||
|
|
||||||
|
byte[] sig = msk.sign(subkey2.toBytes());
|
||||||
|
|
||||||
|
logger.debug("using key {}", Encoder.HEX.encode(subkey1.toBytes()));
|
||||||
|
final byte[] sharedkey = HASH.sha256(HASH.sha256(subkey1.toBytes()));
|
||||||
|
final byte[] xornonce = Arrays.copyOfRange(HASH.sha256(sharedkey), 0, 24);
|
||||||
|
logger.debug("xornonce {}", Encoder.HEX.encode(xornonce));
|
||||||
|
logger.debug("sharedkey {}", Encoder.HEX.encode(sharedkey));
|
||||||
|
|
||||||
|
final byte[] cipher = Util.zeros(96);
|
||||||
|
byte[] msg = Bytes.concat(subkey2.toBytes(), sig);
|
||||||
|
assertEquals(96, msg.length);
|
||||||
|
|
||||||
|
sodium();
|
||||||
|
Sodium.crypto_stream_xsalsa20_xor(cipher, msg, 96, xornonce, sharedkey);
|
||||||
|
assertEquals(96, cipher.length);
|
||||||
|
logger.debug("Clear : {}", Encoder.HEX.encode(msg));
|
||||||
|
logger.debug("Cipher: {}", Encoder.HEX.encode(cipher));
|
||||||
|
msg = Util.zeros(96);
|
||||||
|
Sodium.crypto_stream_xsalsa20_xor(msg, cipher, 96, xornonce, sharedkey);
|
||||||
|
|
||||||
|
final byte[] vkb = Arrays.copyOfRange(msg, 0, 32);
|
||||||
|
sig = Arrays.copyOfRange(msg, 32, 96);
|
||||||
|
logger.debug("vkb : {}", Encoder.HEX.encode(vkb));
|
||||||
|
assertTrue("Verification of signature failed.", mvk.verify(vkb, sig));
|
||||||
|
assertArrayEquals(subkey2.toBytes(), vkb);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSignEncNoncebytes() {
|
public void testSignEncNoncebytes() {
|
||||||
|
logger.debug("testSignEncNoncebytes");
|
||||||
|
|
||||||
final MasterSigningKey msk = new MasterSigningKey(HASH.sha256("TESTSEED".getBytes()));
|
final MasterSigningKey msk = new MasterSigningKey(HASH.sha256("TESTSEED".getBytes()));
|
||||||
final MasterVerifyKey vk = msk.getMasterVerifyKey();
|
final MasterVerifyKey vk = msk.getMasterVerifyKey();
|
||||||
byte[] sig = msk.sign(vk.toBytes());
|
byte[] sig = msk.sign(vk.toBytes());
|
||||||
|
|
|
@ -1,155 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package org.tcpid.opret;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.bitcoinj.core.Sha256Hash;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.libsodium.jni.encoders.Encoder;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.tcpid.key.MasterVerifyKey;
|
|
||||||
import org.tcpid.opret.OPRETECParser;
|
|
||||||
import org.tcpid.opretj.OPRETTransaction;
|
|
||||||
|
|
||||||
import com.google.common.primitives.Bytes;
|
|
||||||
|
|
||||||
public class TestECA1 {
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger(TestECA1.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test method for
|
|
||||||
* {@link org.tcpid.opret.OPRETECParser#pushTransaction(org.tcpid.opretj.OPRETTransaction)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testPushTransaction() {
|
|
||||||
logger.debug("testPushTransaction");
|
|
||||||
|
|
||||||
final byte[] cipher = Encoder.HEX.decode(
|
|
||||||
"a15b671a9890a6bd0b6ed9a50193a15283001ccd72e106198b32242a906c300e263fc31dbfdaad66c40fc9796db3a464ab4313a06bbcd88fc1d503110016114c1da8bdf6e58a82be18d33c1baa96e1a9fe9c6f939b6838b30972be2de53f12d0");
|
|
||||||
final byte[] vkb = Encoder.HEX.decode("fb2e360caf811b3aaf534d0458c2a2ca3e1f213b244a6f83af1ab50eddacdd8c");
|
|
||||||
final MasterVerifyKey mvk = new MasterVerifyKey(vkb);
|
|
||||||
|
|
||||||
final byte[] vkbsha96 = Arrays.copyOfRange(Sha256Hash.of(vkb).getBytes(), 0, 12);
|
|
||||||
final byte[] nullbyte = {};
|
|
||||||
|
|
||||||
List<List<Byte>> opret_data = new ArrayList<>();
|
|
||||||
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca1")));
|
|
||||||
opret_data.add(Bytes.asList(Arrays.copyOfRange(cipher, 0, 48)));
|
|
||||||
opret_data.add(Bytes.asList(vkbsha96));
|
|
||||||
final OPRETTransaction t1 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
|
||||||
|
|
||||||
opret_data = new ArrayList<>();
|
|
||||||
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca2")));
|
|
||||||
opret_data.add(Bytes.asList(Arrays.copyOfRange(cipher, 48, 96)));
|
|
||||||
opret_data.add(Bytes.asList(vkbsha96));
|
|
||||||
final OPRETTransaction t2 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
|
||||||
|
|
||||||
opret_data = new ArrayList<>();
|
|
||||||
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca2")));
|
|
||||||
opret_data.add(Bytes.asList(Arrays.copyOfRange(cipher, 0, 48)));
|
|
||||||
opret_data.add(Bytes.asList(vkbsha96));
|
|
||||||
final OPRETTransaction t3 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
|
||||||
|
|
||||||
opret_data = new ArrayList<>();
|
|
||||||
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca1")));
|
|
||||||
opret_data.add(Bytes.asList(Arrays.copyOfRange(cipher, 48, 96)));
|
|
||||||
opret_data.add(Bytes.asList(vkbsha96));
|
|
||||||
final OPRETTransaction t4 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
|
||||||
|
|
||||||
final OPRETECParser parser = new OPRETECParser();
|
|
||||||
|
|
||||||
parser.addVerifyKey(mvk, 0);
|
|
||||||
|
|
||||||
assertFalse(parser.pushTransaction(t2));
|
|
||||||
assertFalse(parser.pushTransaction(t3));
|
|
||||||
assertFalse(parser.pushTransaction(t4));
|
|
||||||
assertTrue(parser.pushTransaction(t1));
|
|
||||||
|
|
||||||
mvk.clearSubKeys();
|
|
||||||
|
|
||||||
assertFalse(parser.pushTransaction(t1));
|
|
||||||
assertFalse(parser.pushTransaction(t3));
|
|
||||||
assertFalse(parser.pushTransaction(t4));
|
|
||||||
assertTrue(parser.pushTransaction(t2));
|
|
||||||
|
|
||||||
mvk.clearSubKeys();
|
|
||||||
|
|
||||||
assertFalse(parser.pushTransaction(t1));
|
|
||||||
assertFalse(parser.pushTransaction(t4));
|
|
||||||
assertFalse(parser.pushTransaction(t3));
|
|
||||||
assertTrue(parser.pushTransaction(t2));
|
|
||||||
|
|
||||||
mvk.clearSubKeys();
|
|
||||||
|
|
||||||
assertFalse(parser.pushTransaction(t2));
|
|
||||||
assertFalse(parser.pushTransaction(t4));
|
|
||||||
assertFalse(parser.pushTransaction(t3));
|
|
||||||
assertTrue(parser.pushTransaction(t1));
|
|
||||||
final MasterVerifyKey subkey = mvk.getValidSubKey();
|
|
||||||
assertArrayEquals(subkey.toBytes(),
|
|
||||||
Encoder.HEX.decode("e4acb361f4ec55804af6b5a1bbf5ca74ad78b4edc9a977a1dfed08872aa0a5db"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test method for
|
|
||||||
* {@link org.tcpid.opret.OPRETECParser#pushTransaction(org.tcpid.opretj.OPRETTransaction)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testPushTransactionWithNonce() {
|
|
||||||
logger.debug("testPushTransactionWithNonce");
|
|
||||||
final byte[] cipher = Encoder.HEX.decode(
|
|
||||||
"24f99184d03a6ffa5826bd9300a7fb1cff264600f335b3c6042f15cb4d3d9019fa2a9c905cdf6f6c80178def845f0340e6d2e55a7dee433a5af984760adc23e187734e5e4e76aa22f3acab172262633139b6dcd11229fe2385661a70d6c206c0");
|
|
||||||
final byte[] vkb = Encoder.HEX.decode("fb2e360caf811b3aaf534d0458c2a2ca3e1f213b244a6f83af1ab50eddacdd8c");
|
|
||||||
final MasterVerifyKey mvk = new MasterVerifyKey(vkb);
|
|
||||||
|
|
||||||
final byte[] vkbsha96 = Arrays.copyOfRange(Sha256Hash.of(vkb).getBytes(), 0, 12);
|
|
||||||
final byte[] nullbyte = {};
|
|
||||||
|
|
||||||
List<List<Byte>> opret_data = new ArrayList<>();
|
|
||||||
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca1")));
|
|
||||||
final byte[] byte1f = { (byte) 0x11 };
|
|
||||||
opret_data.add(Bytes.asList(Bytes.concat(Arrays.copyOfRange(cipher, 0, 48), byte1f)));
|
|
||||||
opret_data.add(Bytes.asList(vkbsha96));
|
|
||||||
final OPRETTransaction t1 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
|
||||||
|
|
||||||
opret_data = new ArrayList<>();
|
|
||||||
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca2")));
|
|
||||||
opret_data.add(Bytes.asList(Arrays.copyOfRange(cipher, 48, 96)));
|
|
||||||
opret_data.add(Bytes.asList(vkbsha96));
|
|
||||||
final OPRETTransaction t2 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
|
||||||
|
|
||||||
final OPRETECParser parser = new OPRETECParser();
|
|
||||||
|
|
||||||
parser.addVerifyKey(mvk, 0);
|
|
||||||
|
|
||||||
assertFalse(parser.pushTransaction(t2));
|
|
||||||
assertTrue(parser.pushTransaction(t1));
|
|
||||||
|
|
||||||
mvk.clearSubKeys();
|
|
||||||
|
|
||||||
assertFalse(parser.pushTransaction(t1));
|
|
||||||
assertTrue(parser.pushTransaction(t2));
|
|
||||||
|
|
||||||
mvk.clearSubKeys();
|
|
||||||
|
|
||||||
assertFalse(parser.pushTransaction(t1));
|
|
||||||
assertTrue(parser.pushTransaction(t2));
|
|
||||||
|
|
||||||
mvk.clearSubKeys();
|
|
||||||
|
|
||||||
assertFalse(parser.pushTransaction(t2));
|
|
||||||
assertTrue(parser.pushTransaction(t1));
|
|
||||||
final MasterVerifyKey subkey = mvk.getValidSubKey();
|
|
||||||
assertArrayEquals(subkey.toBytes(),
|
|
||||||
Encoder.HEX.decode("fb2e360caf811b3aaf534d0458c2a2ca3e1f213b244a6f83af1ab50eddacdd8c"));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,286 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.tcpid.opret;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.Sha256Hash;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.libsodium.jni.encoders.Encoder;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.tcpid.key.MasterVerifyKey;
|
||||||
|
import org.tcpid.opretj.OPRETTransaction;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
|
|
||||||
|
public class TestPushTransaction {
|
||||||
|
private Logger logger;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
logger = LoggerFactory.getLogger(TestPushTransaction.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test method for
|
||||||
|
* {@link org.tcpid.opret.OPRETECParser#pushTransaction(org.tcpid.opretj.OPRETTransaction)}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testPushTransactionECA12() {
|
||||||
|
logger.debug("testPushTransactionECA12");
|
||||||
|
|
||||||
|
final byte[] cipher = Encoder.HEX.decode(
|
||||||
|
"a15b671a9890a6bd0b6ed9a50193a15283001ccd72e106198b32242a906c300e263fc31dbfdaad66c40fc9796db3a464ab4313a06bbcd88fc1d503110016114c1da8bdf6e58a82be18d33c1baa96e1a9fe9c6f939b6838b30972be2de53f12d0");
|
||||||
|
final byte[] vkb = Encoder.HEX.decode("fb2e360caf811b3aaf534d0458c2a2ca3e1f213b244a6f83af1ab50eddacdd8c");
|
||||||
|
final MasterVerifyKey mvk = new MasterVerifyKey(vkb);
|
||||||
|
|
||||||
|
final byte[] vkbsha96 = Arrays.copyOfRange(Sha256Hash.of(vkb).getBytes(), 0, 12);
|
||||||
|
final byte[] nullbyte = {};
|
||||||
|
|
||||||
|
List<List<Byte>> opret_data = new ArrayList<>();
|
||||||
|
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca1")));
|
||||||
|
opret_data.add(Bytes.asList(Arrays.copyOfRange(cipher, 0, 48)));
|
||||||
|
opret_data.add(Bytes.asList(vkbsha96));
|
||||||
|
final OPRETTransaction t1 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
||||||
|
|
||||||
|
opret_data = new ArrayList<>();
|
||||||
|
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca2")));
|
||||||
|
opret_data.add(Bytes.asList(Arrays.copyOfRange(cipher, 48, 96)));
|
||||||
|
opret_data.add(Bytes.asList(vkbsha96));
|
||||||
|
final OPRETTransaction t2 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
||||||
|
|
||||||
|
// create t3 and t4 to test if the parser handles garbage
|
||||||
|
opret_data = new ArrayList<>();
|
||||||
|
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca2")));
|
||||||
|
opret_data.add(Bytes.asList(Arrays.copyOfRange(cipher, 0, 48)));
|
||||||
|
opret_data.add(Bytes.asList(vkbsha96));
|
||||||
|
final OPRETTransaction t3 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
||||||
|
|
||||||
|
opret_data = new ArrayList<>();
|
||||||
|
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca1")));
|
||||||
|
opret_data.add(Bytes.asList(Arrays.copyOfRange(cipher, 48, 96)));
|
||||||
|
opret_data.add(Bytes.asList(vkbsha96));
|
||||||
|
final OPRETTransaction t4 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
||||||
|
|
||||||
|
final OPRETECParser parser = new OPRETECParser();
|
||||||
|
|
||||||
|
parser.addVerifyKey(mvk, 0);
|
||||||
|
|
||||||
|
assertFalse(parser.pushTransaction(t2));
|
||||||
|
assertFalse(parser.pushTransaction(t3));
|
||||||
|
assertFalse(parser.pushTransaction(t4));
|
||||||
|
assertTrue(parser.pushTransaction(t1));
|
||||||
|
MasterVerifyKey subkey = mvk.getValidSubKey();
|
||||||
|
assertArrayEquals(subkey.toBytes(),
|
||||||
|
Encoder.HEX.decode("e4acb361f4ec55804af6b5a1bbf5ca74ad78b4edc9a977a1dfed08872aa0a5db"));
|
||||||
|
|
||||||
|
mvk.clearSubKeys();
|
||||||
|
|
||||||
|
assertFalse(parser.pushTransaction(t1));
|
||||||
|
assertFalse(parser.pushTransaction(t3));
|
||||||
|
assertFalse(parser.pushTransaction(t4));
|
||||||
|
assertTrue(parser.pushTransaction(t2));
|
||||||
|
subkey = mvk.getValidSubKey();
|
||||||
|
assertArrayEquals(subkey.toBytes(),
|
||||||
|
Encoder.HEX.decode("e4acb361f4ec55804af6b5a1bbf5ca74ad78b4edc9a977a1dfed08872aa0a5db"));
|
||||||
|
|
||||||
|
mvk.clearSubKeys();
|
||||||
|
|
||||||
|
assertFalse(parser.pushTransaction(t1));
|
||||||
|
assertFalse(parser.pushTransaction(t4));
|
||||||
|
assertFalse(parser.pushTransaction(t3));
|
||||||
|
assertTrue(parser.pushTransaction(t2));
|
||||||
|
subkey = mvk.getValidSubKey();
|
||||||
|
assertArrayEquals(subkey.toBytes(),
|
||||||
|
Encoder.HEX.decode("e4acb361f4ec55804af6b5a1bbf5ca74ad78b4edc9a977a1dfed08872aa0a5db"));
|
||||||
|
|
||||||
|
mvk.clearSubKeys();
|
||||||
|
|
||||||
|
assertFalse(parser.pushTransaction(t2));
|
||||||
|
assertFalse(parser.pushTransaction(t4));
|
||||||
|
assertFalse(parser.pushTransaction(t3));
|
||||||
|
assertTrue(parser.pushTransaction(t1));
|
||||||
|
subkey = mvk.getValidSubKey();
|
||||||
|
assertArrayEquals(subkey.toBytes(),
|
||||||
|
Encoder.HEX.decode("e4acb361f4ec55804af6b5a1bbf5ca74ad78b4edc9a977a1dfed08872aa0a5db"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test method for
|
||||||
|
* {@link org.tcpid.opret.OPRETECParser#pushTransaction(org.tcpid.opretj.OPRETTransaction)}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testPushTransactionECA12WithNonce() {
|
||||||
|
logger.debug("testPushTransactionECA12WithNonce");
|
||||||
|
final byte[] cipher = Encoder.HEX.decode(
|
||||||
|
"24f99184d03a6ffa5826bd9300a7fb1cff264600f335b3c6042f15cb4d3d9019fa2a9c905cdf6f6c80178def845f0340e6d2e55a7dee433a5af984760adc23e187734e5e4e76aa22f3acab172262633139b6dcd11229fe2385661a70d6c206c0");
|
||||||
|
final byte[] vkb = Encoder.HEX.decode("fb2e360caf811b3aaf534d0458c2a2ca3e1f213b244a6f83af1ab50eddacdd8c");
|
||||||
|
final MasterVerifyKey mvk = new MasterVerifyKey(vkb);
|
||||||
|
|
||||||
|
final byte[] vkbsha96 = Arrays.copyOfRange(Sha256Hash.of(vkb).getBytes(), 0, 12);
|
||||||
|
final byte[] nullbyte = {};
|
||||||
|
|
||||||
|
List<List<Byte>> opret_data = new ArrayList<>();
|
||||||
|
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca1")));
|
||||||
|
final byte[] byte1f = { (byte) 0x11 };
|
||||||
|
opret_data.add(Bytes.asList(Bytes.concat(Arrays.copyOfRange(cipher, 0, 48), byte1f)));
|
||||||
|
opret_data.add(Bytes.asList(vkbsha96));
|
||||||
|
final OPRETTransaction t1 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
||||||
|
|
||||||
|
opret_data = new ArrayList<>();
|
||||||
|
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca2")));
|
||||||
|
opret_data.add(Bytes.asList(Arrays.copyOfRange(cipher, 48, 96)));
|
||||||
|
opret_data.add(Bytes.asList(vkbsha96));
|
||||||
|
final OPRETTransaction t2 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
||||||
|
|
||||||
|
final OPRETECParser parser = new OPRETECParser();
|
||||||
|
|
||||||
|
parser.addVerifyKey(mvk, 0);
|
||||||
|
|
||||||
|
assertFalse(parser.pushTransaction(t2));
|
||||||
|
assertTrue(parser.pushTransaction(t1));
|
||||||
|
MasterVerifyKey subkey = mvk.getValidSubKey();
|
||||||
|
assertArrayEquals(subkey.toBytes(),
|
||||||
|
Encoder.HEX.decode("fb2e360caf811b3aaf534d0458c2a2ca3e1f213b244a6f83af1ab50eddacdd8c"));
|
||||||
|
|
||||||
|
mvk.clearSubKeys();
|
||||||
|
|
||||||
|
assertFalse(parser.pushTransaction(t1));
|
||||||
|
assertTrue(parser.pushTransaction(t2));
|
||||||
|
subkey = mvk.getValidSubKey();
|
||||||
|
assertArrayEquals(subkey.toBytes(),
|
||||||
|
Encoder.HEX.decode("fb2e360caf811b3aaf534d0458c2a2ca3e1f213b244a6f83af1ab50eddacdd8c"));
|
||||||
|
|
||||||
|
mvk.clearSubKeys();
|
||||||
|
|
||||||
|
assertFalse(parser.pushTransaction(t1));
|
||||||
|
assertTrue(parser.pushTransaction(t2));
|
||||||
|
subkey = mvk.getValidSubKey();
|
||||||
|
assertArrayEquals(subkey.toBytes(),
|
||||||
|
Encoder.HEX.decode("fb2e360caf811b3aaf534d0458c2a2ca3e1f213b244a6f83af1ab50eddacdd8c"));
|
||||||
|
|
||||||
|
mvk.clearSubKeys();
|
||||||
|
|
||||||
|
assertFalse(parser.pushTransaction(t2));
|
||||||
|
assertTrue(parser.pushTransaction(t1));
|
||||||
|
subkey = mvk.getValidSubKey();
|
||||||
|
assertArrayEquals(subkey.toBytes(),
|
||||||
|
Encoder.HEX.decode("fb2e360caf811b3aaf534d0458c2a2ca3e1f213b244a6f83af1ab50eddacdd8c"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test method for
|
||||||
|
* {@link org.tcpid.opret.OPRETECParser#pushTransaction(org.tcpid.opretj.OPRETTransaction)}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testPushTransactionECA34() {
|
||||||
|
logger.debug("testPushTransactionECA34");
|
||||||
|
|
||||||
|
final byte[] cipher = Encoder.HEX.decode(
|
||||||
|
"6c44299f0b00638ca3e8a42d29082fb8f007eaff491472f9329c950b9181bfece5b7bf749b9b941dd92816c62b89f4673848ffe435576ee4e39d2e5f26041daff667c25dee1116a3f9f223de565465cafb2fdf3422c8c905666c268f7244850c");
|
||||||
|
final MasterVerifyKey mvk = new MasterVerifyKey(
|
||||||
|
Encoder.HEX.decode("fb2e360caf811b3aaf534d0458c2a2ca3e1f213b244a6f83af1ab50eddacdd8c"));
|
||||||
|
final MasterVerifyKey firstsub = new MasterVerifyKey(
|
||||||
|
Encoder.HEX.decode("e4acb361f4ec55804af6b5a1bbf5ca74ad78b4edc9a977a1dfed08872aa0a5db"));
|
||||||
|
mvk.setFirstValidSubKey(firstsub, (OPRETTransaction) null, (OPRETTransaction) null);
|
||||||
|
|
||||||
|
final byte[] nullbyte = {};
|
||||||
|
|
||||||
|
List<List<Byte>> opret_data = new ArrayList<>();
|
||||||
|
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca3")));
|
||||||
|
opret_data.add(Bytes.asList(Arrays.copyOfRange(cipher, 0, 48)));
|
||||||
|
opret_data.add(Bytes.asList(mvk.getShortHash()));
|
||||||
|
opret_data.add(Bytes.asList(firstsub.getShortHash()));
|
||||||
|
final OPRETTransaction t1 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
||||||
|
|
||||||
|
opret_data = new ArrayList<>();
|
||||||
|
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca4")));
|
||||||
|
opret_data.add(Bytes.asList(Arrays.copyOfRange(cipher, 48, 96)));
|
||||||
|
opret_data.add(Bytes.asList(mvk.getShortHash()));
|
||||||
|
opret_data.add(Bytes.asList(firstsub.getShortHash()));
|
||||||
|
final OPRETTransaction t2 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
||||||
|
|
||||||
|
// create t3 and t4 to test if the parser handles garbage
|
||||||
|
opret_data = new ArrayList<>();
|
||||||
|
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca4")));
|
||||||
|
opret_data.add(Bytes.asList(Arrays.copyOfRange(cipher, 0, 48)));
|
||||||
|
opret_data.add(Bytes.asList(mvk.getShortHash()));
|
||||||
|
opret_data.add(Bytes.asList(firstsub.getShortHash()));
|
||||||
|
final OPRETTransaction t3 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
||||||
|
|
||||||
|
opret_data = new ArrayList<>();
|
||||||
|
opret_data.add(Bytes.asList(Encoder.HEX.decode("eca3")));
|
||||||
|
opret_data.add(Bytes.asList(Arrays.copyOfRange(cipher, 48, 96)));
|
||||||
|
opret_data.add(Bytes.asList(mvk.getShortHash()));
|
||||||
|
opret_data.add(Bytes.asList(firstsub.getShortHash()));
|
||||||
|
final OPRETTransaction t4 = new OPRETTransaction(Sha256Hash.of(nullbyte), Sha256Hash.of(nullbyte), opret_data);
|
||||||
|
|
||||||
|
final OPRETECParser parser = new OPRETECParser();
|
||||||
|
|
||||||
|
parser.addVerifyKey(mvk, 0);
|
||||||
|
parser.addVerifyKey(firstsub, 0);
|
||||||
|
|
||||||
|
assertFalse(parser.pushTransaction(t2));
|
||||||
|
assertFalse(parser.pushTransaction(t3));
|
||||||
|
assertFalse(parser.pushTransaction(t4));
|
||||||
|
assertTrue(parser.pushTransaction(t1));
|
||||||
|
|
||||||
|
mvk.revokeSubKey(firstsub);
|
||||||
|
MasterVerifyKey subkey = mvk.getValidSubKey();
|
||||||
|
assertArrayEquals(subkey.toBytes(),
|
||||||
|
Encoder.HEX.decode("11e14458b16050a23a772e469ee424f513c3eb81682c0f9f81f07e607c6bf917"));
|
||||||
|
|
||||||
|
mvk.clearSubKeys();
|
||||||
|
mvk.setFirstValidSubKey(firstsub, (OPRETTransaction) null, (OPRETTransaction) null);
|
||||||
|
|
||||||
|
assertFalse(parser.pushTransaction(t1));
|
||||||
|
assertFalse(parser.pushTransaction(t3));
|
||||||
|
assertFalse(parser.pushTransaction(t4));
|
||||||
|
assertTrue(parser.pushTransaction(t2));
|
||||||
|
|
||||||
|
mvk.revokeSubKey(firstsub);
|
||||||
|
subkey = mvk.getValidSubKey();
|
||||||
|
assertArrayEquals(subkey.toBytes(),
|
||||||
|
Encoder.HEX.decode("11e14458b16050a23a772e469ee424f513c3eb81682c0f9f81f07e607c6bf917"));
|
||||||
|
|
||||||
|
mvk.clearSubKeys();
|
||||||
|
mvk.setFirstValidSubKey(firstsub, (OPRETTransaction) null, (OPRETTransaction) null);
|
||||||
|
|
||||||
|
assertFalse(parser.pushTransaction(t1));
|
||||||
|
assertFalse(parser.pushTransaction(t4));
|
||||||
|
assertFalse(parser.pushTransaction(t3));
|
||||||
|
assertTrue(parser.pushTransaction(t2));
|
||||||
|
|
||||||
|
mvk.revokeSubKey(firstsub);
|
||||||
|
subkey = mvk.getValidSubKey();
|
||||||
|
assertArrayEquals(subkey.toBytes(),
|
||||||
|
Encoder.HEX.decode("11e14458b16050a23a772e469ee424f513c3eb81682c0f9f81f07e607c6bf917"));
|
||||||
|
|
||||||
|
mvk.clearSubKeys();
|
||||||
|
mvk.setFirstValidSubKey(firstsub, (OPRETTransaction) null, (OPRETTransaction) null);
|
||||||
|
|
||||||
|
assertFalse(parser.pushTransaction(t2));
|
||||||
|
assertFalse(parser.pushTransaction(t4));
|
||||||
|
assertFalse(parser.pushTransaction(t3));
|
||||||
|
assertTrue(parser.pushTransaction(t1));
|
||||||
|
|
||||||
|
mvk.revokeSubKey(firstsub);
|
||||||
|
subkey = mvk.getValidSubKey();
|
||||||
|
assertArrayEquals(subkey.toBytes(),
|
||||||
|
Encoder.HEX.decode("11e14458b16050a23a772e469ee424f513c3eb81682c0f9f81f07e607c6bf917"));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue