diff --git a/src/main/java/org/arkecosystem/crypto/enums/CoreTransactionTypes.java b/src/main/java/org/arkecosystem/crypto/enums/CoreTransactionTypes.java index 5ee7d0de..a977cb48 100644 --- a/src/main/java/org/arkecosystem/crypto/enums/CoreTransactionTypes.java +++ b/src/main/java/org/arkecosystem/crypto/enums/CoreTransactionTypes.java @@ -6,12 +6,10 @@ public enum CoreTransactionTypes { VALIDATOR_REGISTRATION(2), VOTE(3), MULTI_SIGNATURE_REGISTRATION(4), - IPFS(5), MULTI_PAYMENT(6), VALIDATOR_RESIGNATION(7), - HTLC_LOCK(8), - HTLC_CLAIM(9), - HTLC_REFUND(10); + USERNAME_REGISTRATION(8), + USERNAME_RESIGNATION(9); private final int value; diff --git a/src/main/java/org/arkecosystem/crypto/enums/Fees.java b/src/main/java/org/arkecosystem/crypto/enums/Fees.java index e5e1321b..8a5cf991 100644 --- a/src/main/java/org/arkecosystem/crypto/enums/Fees.java +++ b/src/main/java/org/arkecosystem/crypto/enums/Fees.java @@ -6,12 +6,10 @@ public enum Fees { VALIDATOR_REGISTRATION(2_500_000_000L), VOTE(100_000_000L), MULTI_SIGNATURE_REGISTRATION(500_000_000L), - IPFS(500_000_000L), MULTI_PAYMENT(10_000_000L), VALIDATOR_RESIGNATION(2_500_000_000L), - HTLC_LOCK(10_000_000L), - HTLC_CLAIM(0L), - HTLC_REFUND(0L); + USERNAME_REGISTRATION(2_500_000_000L), + USERNAME_RESIGNATION(2_500_000_000L); private final Long value; diff --git a/src/main/java/org/arkecosystem/crypto/transactions/Deserializer.java b/src/main/java/org/arkecosystem/crypto/transactions/Deserializer.java index 32730ef9..66c45891 100644 --- a/src/main/java/org/arkecosystem/crypto/transactions/Deserializer.java +++ b/src/main/java/org/arkecosystem/crypto/transactions/Deserializer.java @@ -15,6 +15,8 @@ import org.arkecosystem.crypto.transactions.types.SecondSignatureRegistration; import org.arkecosystem.crypto.transactions.types.Transaction; import org.arkecosystem.crypto.transactions.types.Transfer; +import org.arkecosystem.crypto.transactions.types.UsernameRegistration; +import org.arkecosystem.crypto.transactions.types.UsernameResignation; import org.arkecosystem.crypto.transactions.types.ValidatorRegistration; import org.arkecosystem.crypto.transactions.types.ValidatorResignation; import org.arkecosystem.crypto.transactions.types.Vote; @@ -42,6 +44,10 @@ public Deserializer(String serialized) { coreTransactionTypes.put(CoreTransactionTypes.MULTI_PAYMENT.getValue(), new MultiPayment()); coreTransactionTypes.put( CoreTransactionTypes.VALIDATOR_RESIGNATION.getValue(), new ValidatorResignation()); + coreTransactionTypes.put( + CoreTransactionTypes.USERNAME_RESIGNATION.getValue(), new UsernameResignation()); + coreTransactionTypes.put( + CoreTransactionTypes.USERNAME_REGISTRATION.getValue(), new UsernameRegistration()); transactionGroups.put(TransactionTypeGroup.CORE.getValue(), coreTransactionTypes); diff --git a/src/main/java/org/arkecosystem/crypto/transactions/TransactionAsset.java b/src/main/java/org/arkecosystem/crypto/transactions/TransactionAsset.java index b69e19bc..5d0fef1d 100644 --- a/src/main/java/org/arkecosystem/crypto/transactions/TransactionAsset.java +++ b/src/main/java/org/arkecosystem/crypto/transactions/TransactionAsset.java @@ -13,6 +13,7 @@ public class TransactionAsset { public HashMap customAsset = new HashMap<>(); public long amount = 0L; public String validatorPublicKey; + public String username; public static class Signature { public String publicKey; diff --git a/src/main/java/org/arkecosystem/crypto/transactions/builder/UsernameRegistrationBuilder.java b/src/main/java/org/arkecosystem/crypto/transactions/builder/UsernameRegistrationBuilder.java new file mode 100644 index 00000000..19592102 --- /dev/null +++ b/src/main/java/org/arkecosystem/crypto/transactions/builder/UsernameRegistrationBuilder.java @@ -0,0 +1,29 @@ +package org.arkecosystem.crypto.transactions.builder; + +import org.arkecosystem.crypto.enums.Fees; +import org.arkecosystem.crypto.transactions.types.Transaction; +import org.arkecosystem.crypto.transactions.types.UsernameRegistration; + +public class UsernameRegistrationBuilder + extends AbstractTransactionBuilder { + public UsernameRegistrationBuilder() { + super(); + this.transaction.fee = Fees.VALIDATOR_REGISTRATION.getValue(); + } + + public UsernameRegistrationBuilder usernameAsset(String username) { + this.transaction.asset.username = username; + + return this; + } + + @Override + public Transaction getTransactionInstance() { + return new UsernameRegistration(); + } + + @Override + public UsernameRegistrationBuilder instance() { + return this; + } +} diff --git a/src/main/java/org/arkecosystem/crypto/transactions/builder/UsernameResignationBuilder.java b/src/main/java/org/arkecosystem/crypto/transactions/builder/UsernameResignationBuilder.java new file mode 100644 index 00000000..7fee046d --- /dev/null +++ b/src/main/java/org/arkecosystem/crypto/transactions/builder/UsernameResignationBuilder.java @@ -0,0 +1,24 @@ +package org.arkecosystem.crypto.transactions.builder; + +import org.arkecosystem.crypto.enums.Fees; +import org.arkecosystem.crypto.transactions.types.Transaction; +import org.arkecosystem.crypto.transactions.types.UsernameResignation; + +public class UsernameResignationBuilder + extends AbstractTransactionBuilder { + + public UsernameResignationBuilder() { + super(); + this.transaction.fee = Fees.USERNAME_RESIGNATION.getValue(); + } + + @Override + public Transaction getTransactionInstance() { + return new UsernameResignation(); + } + + @Override + public UsernameResignationBuilder instance() { + return this; + } +} diff --git a/src/main/java/org/arkecosystem/crypto/transactions/types/Transaction.java b/src/main/java/org/arkecosystem/crypto/transactions/types/Transaction.java index 0530eca3..0e61dfe0 100644 --- a/src/main/java/org/arkecosystem/crypto/transactions/types/Transaction.java +++ b/src/main/java/org/arkecosystem/crypto/transactions/types/Transaction.java @@ -4,9 +4,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; -import java.util.Set; import org.arkecosystem.crypto.encoding.Hex; import org.arkecosystem.crypto.identities.PrivateKey; import org.arkecosystem.crypto.signature.SchnorrSigner; @@ -93,7 +91,7 @@ public boolean verify() { byte[] signature = Hex.decode(this.signature); byte[] hash = Sha256Hash.hash(Serializer.serialize(this, true, true, false)); - return verifier(this.signature).verify(hash, keys, signature); + return verifier().verify(hash, keys, signature); } public boolean secondVerify(String secondPublicKey) { @@ -102,48 +100,7 @@ public boolean secondVerify(String secondPublicKey) { byte[] signature = Hex.decode(this.secondSignature); byte[] hash = Sha256Hash.hash(Serializer.serialize(this, false, true, false)); - return verifier(this.secondSignature).verify(hash, keys, signature); - } - - public boolean multiVerify(int min, List publicKeys) { - if (publicKeys.isEmpty()) { - throw new RuntimeException("The multi signature asset is invalid."); - } - - byte[] hash = Sha256Hash.hash(Serializer.serialize(this, true, true, true)); - - Set publicKeyIndexes = new HashSet<>(); - int verifiedSignatures = 0; - boolean verified = false; - for (int i = 0; i < this.signatures.size(); i++) { - String signature = this.signatures.get(i); - int publicKeyIndex = Integer.parseInt(signature.substring(0, 2), 16); - - if (!publicKeyIndexes.contains(publicKeyIndex)) { - publicKeyIndexes.add(publicKeyIndex); - } else { - throw new RuntimeException("Duplicate participant in multi signature"); - } - - String partialSignature = signature.substring(2); - String publicKey = publicKeys.get(publicKeyIndex); - - if (verifier(partialSignature) - .verify( - hash, - ECKey.fromPublicOnly(Hex.decode(publicKey)), - Hex.decode(partialSignature))) { - verifiedSignatures++; - } - - if (verifiedSignatures == min) { - verified = true; - break; - } else if (signatures.size() - (i + 1 - verifiedSignatures) < min) { - break; - } - } - return verified; + return verifier().verify(hash, keys, signature); } public String toJson() { @@ -206,7 +163,7 @@ private Signer signer() { return new SchnorrSigner(); } - private Verifier verifier(String signature) { + private Verifier verifier() { return new SchnorrVerifier(); } } diff --git a/src/main/java/org/arkecosystem/crypto/transactions/types/UsernameRegistration.java b/src/main/java/org/arkecosystem/crypto/transactions/types/UsernameRegistration.java new file mode 100644 index 00000000..f4bbe80d --- /dev/null +++ b/src/main/java/org/arkecosystem/crypto/transactions/types/UsernameRegistration.java @@ -0,0 +1,53 @@ +package org.arkecosystem.crypto.transactions.types; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.HashMap; +import org.arkecosystem.crypto.enums.CoreTransactionTypes; +import org.arkecosystem.crypto.enums.TransactionTypeGroup; + +public class UsernameRegistration extends Transaction { + @Override + public int getTransactionType() { + return CoreTransactionTypes.USERNAME_REGISTRATION.getValue(); + } + + @Override + public int getTransactionTypeGroup() { + return TransactionTypeGroup.CORE.getValue(); + } + + @Override + public HashMap assetToHashMap() { + HashMap asset = new HashMap<>(); + + asset.put("username", this.asset.username); + + return asset; + } + + @Override + public byte[] serialize() { + byte[] username = this.asset.username.getBytes(); + + ByteBuffer buffer = ByteBuffer.allocate(username.length + 1); + + buffer.order(ByteOrder.LITTLE_ENDIAN); + + buffer.put((byte) username.length); + buffer.put(username); + + return buffer.array(); + } + + @Override + public void deserialize(ByteBuffer buffer) { + int usernameLength = buffer.get() & 0xff; + + byte[] username = new byte[usernameLength]; + buffer.get(username); + + String utf8Username = new String(username); + this.asset.username = utf8Username; + } +} diff --git a/src/main/java/org/arkecosystem/crypto/transactions/types/UsernameResignation.java b/src/main/java/org/arkecosystem/crypto/transactions/types/UsernameResignation.java new file mode 100644 index 00000000..8f1b70b2 --- /dev/null +++ b/src/main/java/org/arkecosystem/crypto/transactions/types/UsernameResignation.java @@ -0,0 +1,31 @@ +package org.arkecosystem.crypto.transactions.types; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import org.arkecosystem.crypto.enums.CoreTransactionTypes; +import org.arkecosystem.crypto.enums.TransactionTypeGroup; + +public class UsernameResignation extends Transaction { + @Override + public int getTransactionType() { + return CoreTransactionTypes.USERNAME_RESIGNATION.getValue(); + } + + @Override + public int getTransactionTypeGroup() { + return TransactionTypeGroup.CORE.getValue(); + } + + @Override + public HashMap assetToHashMap() { + return null; + } + + @Override + public byte[] serialize() { + return new byte[0]; + } + + @Override + public void deserialize(ByteBuffer buffer) {} +} diff --git a/src/main/java/org/arkecosystem/crypto/Schnorr.java b/src/main/java/org/arkecosystem/crypto/utils/Schnorr.java similarity index 100% rename from src/main/java/org/arkecosystem/crypto/Schnorr.java rename to src/main/java/org/arkecosystem/crypto/utils/Schnorr.java diff --git a/src/test/java/org/arkecosystem/crypto/signature/FixtureSignVerificationTest.java b/src/test/java/org/arkecosystem/crypto/signature/FixtureSignVerificationTest.java index 73294eda..c338e6ec 100644 --- a/src/test/java/org/arkecosystem/crypto/signature/FixtureSignVerificationTest.java +++ b/src/test/java/org/arkecosystem/crypto/signature/FixtureSignVerificationTest.java @@ -1,60 +1,31 @@ package org.arkecosystem.crypto.signature; -import static org.hamcrest.CoreMatchers.startsWith; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertTrue; import com.google.gson.internal.LinkedTreeMap; -import java.util.Arrays; -import java.util.List; -import org.arkecosystem.crypto.encoding.Hex; import org.arkecosystem.crypto.identities.PublicKey; import org.arkecosystem.crypto.transactions.Deserializer; import org.arkecosystem.crypto.transactions.FixtureLoader; -import org.arkecosystem.crypto.transactions.Serializer; import org.arkecosystem.crypto.transactions.types.Transaction; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; public class FixtureSignVerificationTest { - private final String passphrase = "my super secret passphrase"; private final String secondPassphrase = "this is a top secret second passphrase"; - private final String musigPassphrase1 = - "album pony urban cheap small blade cannon silent run reveal luxury glad predict excess fire beauty hollow reward solar egg exclude leaf sight degree"; - private final String musigPassphrase2 = - "hen slogan retire boss upset blame rocket slender area arch broom bring elder few milk bounce execute page evoke once inmate pear marine deliver"; - private final String musigPassphrase3 = - "top visa use bacon sun infant shrimp eye bridge fantasy chair sadness stable simple salad canoe raw hill target connect avoid promote spider category"; @ParameterizedTest @ValueSource( strings = { "transactions/transfer/transfer-sign", - "transactions/transfer/transfer-with-vendor-field-sign", - // "transactions/transfer/transfer-multi-sign", - "transactions/vote/vote-sign", "transactions/vote/unvote-sign", - // "transactions/vote/vote-multi-sign", - "transactions/validator_registration/validator-registration-sign", - // "transactions/validator_registration/validator-registration-multi-sign", - "transactions/validator_resignation/validator-resignation-sign", - // "transactions/validator_resignation/validator-resignation-multi-sign", - "transactions/multi_payment/multi-payment-sign", "transactions/multi_payment/multi-payment-with-vendor-field-sign", - // "transactions/multi_payment/multi-payment-multi-sign", - - // "transactions/username_resignation/username-resignation-sign", - // "transactions/username_resignation/username-resignation-multi-sign", - - // "transactions/username_registration/username-registration-multi-sign", - // "transactions/username_registration/username-registration-sign", - + "transactions/username_resignation/username-resignation-sign", + "transactions/username_registration/username-registration-sign", "transactions/multi_signature_registration/multi-signature-registration-sign", }) void checkSchnorrSignature(String file) { @@ -67,117 +38,10 @@ void checkSchnorrSignature(String file) { if (actual.secondSignature != null) { checkSecondSignature(actual); } - - if (actual.signatures != null) { - checkMultiSignature(actual); - } - } - - @ParameterizedTest - @ValueSource( - strings = { - "transactions/transfer/transfer-sign", - "transactions/transfer/transfer-with-vendor-field-sign", - // "transactions/transfer/transfer-multi-sign", - - "transactions/vote/vote-sign", - "transactions/vote/unvote-sign", - // "transactions/vote/vote-multi-sign", - - "transactions/validator_registration/validator-registration-sign", - // "transactions/validator_registration/validator-registration-multi-sign", - - "transactions/validator_resignation/validator-resignation-sign", - // "transactions/validator_resignation/validator-resignation-multi-sign", - - "transactions/multi_payment/multi-payment-sign", - "transactions/multi_payment/multi-payment-with-vendor-field-sign", - // "transactions/multi_payment/multi-payment-multi-sign", - - // "transactions/username_resignation/username-resignation-sign", - // "transactions/username_resignation/username-resignation-multi-sign", - - // "transactions/username_registration/username-registration-multi-sign", - // "transactions/username_registration/username-registration-sign", - - // "transactions/multi_signature_registration/multi-signature-registration-sign", - }) - void checkSigningAgainProducesSameSignature(String file) { - LinkedTreeMap fixture = FixtureLoader.load(file); - - Transaction actual = new Deserializer(fixture.get("serialized").toString()).deserialize(); - - // Remove the signatures from original transaction - Transaction withoutSignatures = - new Deserializer(Hex.encode(Serializer.serialize(actual, true, true, true))) - .deserialize(); - - // Ensure only the signatures were removed - assertThat( - fixture.get("serialized").toString(), - startsWith(Hex.encode(Serializer.serialize(withoutSignatures)))); - - reSignUnsigned(actual, withoutSignatures); - - if (withoutSignatures.signature != null) { - assertTrue(withoutSignatures.verify()); - } - - if (withoutSignatures.secondSignature != null) { - checkSecondSignature(withoutSignatures); - } - - int signatureLength = 128; - - if (withoutSignatures.signatures != null) { - checkMultiSignature(withoutSignatures); - - signatureLength = 128 + (withoutSignatures.signatures.size() * 130); - } - - String serializedWithoutSignatures = Hex.encode(Serializer.serialize(withoutSignatures)); - String serializedFixture = fixture.get("serialized").toString(); - - // Exclude the last 128 characters (signature) for final comparison - assertThat( - serializedWithoutSignatures.substring( - 0, serializedWithoutSignatures.length() - signatureLength), - is(serializedFixture.substring(0, serializedFixture.length() - signatureLength))); - } - - private void reSignUnsigned(Transaction actual, Transaction withoutSignatures) { - if (actual.signatures != null) { - int i = 0; - for (String passphrase : - Arrays.asList(musigPassphrase1, musigPassphrase2, musigPassphrase3)) { - withoutSignatures.multiSign(passphrase, i++); - } - if (actual.signature != null) { - withoutSignatures.sign(musigPassphrase1); - } - if (actual.secondSignature != null) { - withoutSignatures.secondSign(secondPassphrase); - } - } else if (actual.secondSignature != null) { - withoutSignatures.sign(passphrase); - withoutSignatures.secondSign(secondPassphrase); - } else if (actual.signature != null) { - withoutSignatures.sign(passphrase); - } } private void checkSecondSignature(Transaction actual) { String secondPublicKey = PublicKey.fromPassphrase(secondPassphrase); assertTrue(actual.secondVerify(secondPublicKey)); } - - private void checkMultiSignature(Transaction actual) { - String key1 = PublicKey.fromPassphrase(musigPassphrase1); - String key2 = PublicKey.fromPassphrase(musigPassphrase2); - String key3 = PublicKey.fromPassphrase(musigPassphrase3); - - List publicKeys = Arrays.asList(key1, key2, key3); - - assertTrue(actual.multiVerify(2, publicKeys)); - } } diff --git a/src/test/java/org/arkecosystem/crypto/transactions/builder/MultiPaymentBuilderTest.java b/src/test/java/org/arkecosystem/crypto/transactions/builder/MultiPaymentBuilderTest.java index 4427b45e..ab66bd60 100644 --- a/src/test/java/org/arkecosystem/crypto/transactions/builder/MultiPaymentBuilderTest.java +++ b/src/test/java/org/arkecosystem/crypto/transactions/builder/MultiPaymentBuilderTest.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import org.arkecosystem.crypto.transactions.types.Transaction; import org.junit.jupiter.api.Test; @@ -59,4 +60,29 @@ void testMaxPayments() { () -> actual.addPayment("0xb693449AdDa7EFc015D87944EAE8b7C37EB1690A", 1)); assertEquals("Expected a maximum of 64 payments", exception.getMessage()); } + + @Test + void buildMultiSignature() { + Transaction actual = + new MultiPaymentBuilder() + .addPayment("0xb693449AdDa7EFc015D87944EAE8b7C37EB1690A", 1) + .addPayment("0xb693449AdDa7EFc015D87944EAE8b7C37EB1690A", 2) + .addPayment("0xb693449AdDa7EFc015D87944EAE8b7C37EB1690A", 3) + .vendorField("This is a transaction from Java") + .multiSign("secret 1", 0) + .multiSign("secret 2", 1) + .multiSign("secret 3", 2) + .sign("this is a top secret passphrase") + .transaction; + + assertTrue(actual.verify()); + + HashMap actualHashMap = actual.toHashMap(); + + assertNotNull(actualHashMap.get("signatures")); + + List actualSignatures = (List) actualHashMap.get("signatures"); + + assertEquals(3, actualSignatures.size()); + } } diff --git a/src/test/java/org/arkecosystem/crypto/transactions/builder/MultiSignatureRegistrationBuilderTest.java b/src/test/java/org/arkecosystem/crypto/transactions/builder/MultiSignatureRegistrationBuilderTest.java index 894ab34c..3751034f 100644 --- a/src/test/java/org/arkecosystem/crypto/transactions/builder/MultiSignatureRegistrationBuilderTest.java +++ b/src/test/java/org/arkecosystem/crypto/transactions/builder/MultiSignatureRegistrationBuilderTest.java @@ -3,14 +3,11 @@ import static org.junit.jupiter.api.Assertions.*; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; import org.arkecosystem.crypto.enums.Fees; import org.arkecosystem.crypto.identities.PublicKey; -import org.arkecosystem.crypto.transactions.Deserializer; import org.arkecosystem.crypto.transactions.types.Transaction; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class MultiSignatureRegistrationBuilderTest { @@ -38,7 +35,6 @@ void build() { .transaction; assertTrue(actual.verify()); - assertTrue(actual.multiVerify(3, publicKeys)); HashMap actualHashMap = actual.toHashMap(); @@ -54,32 +50,4 @@ void build() { assertEquals(publicKeys, actualPublicKeys); assertEquals(3, actualMin); } - - @Test - void checkMultiSignaturePassingInvalidMultiSignatureAsset() { - Exception thrown = - Assertions.assertThrows( - RuntimeException.class, - () -> { - Deserializer deserializer = - new Deserializer( - "ff011e0100000004000200000000000000023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d30065cd1d00000000000203029fab3cb2f5e248ae7cbb4de646741da4d73c493b2a03ab5c71507fb2c0dcca9203629f9dbf7f1e91cefa845126189816ceae357bdd1f41bd14787318a7d5b55d48027941d2059f89a26d89e87d3385e261a0ede1234aaeaa487012b69d6b67962dc52b33558cdc62933ff56feb646d1f47a98104bf34b894895d5e816f86e556f87fce8485e55aa32dfa1cd86456a66a58ef7a68dff4af51e2f7fcf75b983540872e000caa6864c71362b369c71107f463f29c43c361e54260cbc54d791b7385dbe76f29d12b9befbe4f98792d7046481afcf0c156408310192a93d8413e5380438f270153a22c5ce2b1894f0a141adc19de567077d2d268f4c7e1476e9558ecb4411d486cd0d7aa3e9c7716739a055a8a1a64a162d0362645d63d13791a9876ef8b5a88021d56997f0c9e21201c59e1b7b6be8d5a609908a4f65bf266144baf5e61e3f14bc2651f62187f4ffa17c8b010fcb0fba94a04df56bc25e5cb20935ec5fb7ad632"); - Transaction actual = deserializer.deserialize(); - assertTrue(actual.multiVerify(3, Collections.emptyList())); - }); - assertEquals("The multi signature asset is invalid.", thrown.getMessage()); - } - - @Test - void checkMultiSignaturePassingInvalidMultiSignatureAssets() { - String key1 = PublicKey.fromPassphrase("this is a top secret passphrase 1"); - String key2 = PublicKey.fromPassphrase("this is a top secret passphrase 2"); - String key3 = PublicKey.fromPassphrase("this is a top secret passphrase 3"); - - Deserializer deserializer = - new Deserializer( - "ff011e0100000004000200000000000000023efc1da7f315f3c533a4080e491f32cd4219731cef008976c3876539e1f192d30065cd1d00000000000203029fab3cb2f5e248ae7cbb4de646741da4d73c493b2a03ab5c71507fb2c0dcca9203629f9dbf7f1e91cefa845126189816ceae357bdd1f41bd14787318a7d5b55d48027941d2059f89a26d89e87d3385e261a0ede1234aaeaa487012b69d6b67962dc52b33558cdc62933ff56feb646d1f47a98104bf34b894895d5e816f86e556f87fce8485e55aa32dfa1cd86456a66a58ef7a68dff4af51e2f7fcf75b983540872e000caa6864c71362b369c71107f463f29c43c361e54260cbc54d791b7385dbe76f29d12b9befbe4f98792d7046481afcf0c156408310192a93d8413e5380438f270153a22c5ce2b1894f0a141adc19de567077d2d268f4c7e1476e9558ecb4411d486cd0d7aa3e9c7716739a055a8a1a64a162d0362645d63d13791a9876ef8b5a88021d56997f0c9e21201c59e1b7b6be8d5a609908a4f65bf266144baf5e61e3f14bc2651f62187f4ffa17c8b010fcb0fba94a04df56bc25e5cb20935ec5fb7ad632"); - Transaction actual = deserializer.deserialize(); - assertFalse(actual.multiVerify(3, Arrays.asList(key1, key2, key3))); - } } diff --git a/src/test/java/org/arkecosystem/crypto/transactions/builder/TransferBuilderTest.java b/src/test/java/org/arkecosystem/crypto/transactions/builder/TransferBuilderTest.java index 22634cd2..00e061af 100644 --- a/src/test/java/org/arkecosystem/crypto/transactions/builder/TransferBuilderTest.java +++ b/src/test/java/org/arkecosystem/crypto/transactions/builder/TransferBuilderTest.java @@ -1,9 +1,11 @@ package org.arkecosystem.crypto.transactions.builder; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.HashMap; +import java.util.List; import org.arkecosystem.crypto.enums.Fees; import org.arkecosystem.crypto.transactions.types.Transaction; import org.junit.jupiter.api.Test; @@ -62,4 +64,31 @@ void buildSecondSignature() { HashMap actualHashMap = actual.toHashMap(); assertEquals(actualHashMap.get("secondSignature"), actual.secondSignature); } + + @Test + void buildMultiSignature() { + Transaction actual = + new TransferBuilder() + .recipient("0xb693449AdDa7EFc015D87944EAE8b7C37EB1690A") + .amount(133380000000L) + .expiration(100000) + .vendorField("This is a transaction from Java") + .nonce(3) + .fee(Fees.TRANSFER.getValue()) + .multiSign("secret 1", 0) + .multiSign("secret 2", 1) + .multiSign("secret 3", 2) + .sign("secret 1") + .transaction; + + assertTrue(actual.verify()); + + HashMap actualHashMap = actual.toHashMap(); + + assertNotNull(actualHashMap.get("signatures")); + + List actualSignatures = (List) actualHashMap.get("signatures"); + + assertEquals(3, actualSignatures.size()); + } } diff --git a/src/test/java/org/arkecosystem/crypto/transactions/builder/UsernameRegistrationBuilderTest.java b/src/test/java/org/arkecosystem/crypto/transactions/builder/UsernameRegistrationBuilderTest.java new file mode 100644 index 00000000..d373b3f5 --- /dev/null +++ b/src/test/java/org/arkecosystem/crypto/transactions/builder/UsernameRegistrationBuilderTest.java @@ -0,0 +1,51 @@ +package org.arkecosystem.crypto.transactions.builder; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.HashMap; +import java.util.List; +import org.arkecosystem.crypto.transactions.types.Transaction; +import org.junit.jupiter.api.Test; + +class UsernameRegistrationBuilderTest { + @Test + void build() { + Transaction actual = + new UsernameRegistrationBuilder() + .usernameAsset("alfonsobries") + .nonce(3) + .sign("this is a top secret passphrase") + .transaction; + + HashMap actualHashMap = actual.toHashMap(); + + HashMap asset = (HashMap) actualHashMap.get("asset"); + + assertEquals(asset.get("username"), "alfonsobries"); + + assertTrue(actual.verify()); + } + + @Test + void buildMultiSignature() { + Transaction actual = + new UsernameRegistrationBuilder() + .usernameAsset("alfonsobries") + .nonce(3) + .multiSign("secret 1", 0) + .multiSign("secret 2", 1) + .multiSign("secret 3", 2) + .sign("this is a top secret passphrase") + .transaction; + + assertTrue(actual.verify()); + + HashMap actualHashMap = actual.toHashMap(); + + assertNotNull(actualHashMap.get("signatures")); + + List actualSignatures = (List) actualHashMap.get("signatures"); + + assertEquals(3, actualSignatures.size()); + } +} diff --git a/src/test/java/org/arkecosystem/crypto/transactions/builder/UsernameResignationBuilderTest.java b/src/test/java/org/arkecosystem/crypto/transactions/builder/UsernameResignationBuilderTest.java new file mode 100644 index 00000000..e96e39ed --- /dev/null +++ b/src/test/java/org/arkecosystem/crypto/transactions/builder/UsernameResignationBuilderTest.java @@ -0,0 +1,62 @@ +package org.arkecosystem.crypto.transactions.builder; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.HashMap; +import java.util.List; +import org.arkecosystem.crypto.transactions.types.Transaction; +import org.junit.jupiter.api.Test; + +public class UsernameResignationBuilderTest { + @Test + void build() { + Transaction actual = + new UsernameResignationBuilder() + .nonce(3) + .sign("this is a top secret passphrase") + .transaction; + + HashMap actualHashMap = actual.toHashMap(); + HashMap actualAsset = (HashMap) actualHashMap.get("asset"); + assertNull(actualAsset); + + assertTrue(actual.verify()); + } + + @Test + void buildSecondSignature() { + Transaction actual = + new UsernameResignationBuilder() + .nonce(3) + .sign("this is a top secret passphrase") + .secondSign("this is a top secret second passphrase") + .transaction; + + assertTrue(actual.verify()); + assertTrue( + actual.secondVerify( + "03699e966b2525f9088a6941d8d94f7869964a000efe65783d78ac82e1199fe609")); + } + + @Test + void buildMultiSignature() { + Transaction actual = + new UsernameResignationBuilder() + .nonce(3) + .multiSign("secret 1", 0) + .multiSign("secret 2", 1) + .multiSign("secret 3", 2) + .sign("this is a top secret passphrase") + .transaction; + + assertTrue(actual.verify()); + + HashMap actualHashMap = actual.toHashMap(); + + assertNotNull(actualHashMap.get("signatures")); + + List actualSignatures = (List) actualHashMap.get("signatures"); + + assertEquals(3, actualSignatures.size()); + } +} diff --git a/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorRegistrationBuilderTest.java b/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorRegistrationBuilderTest.java index 1a28a767..65ffa8f8 100644 --- a/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorRegistrationBuilderTest.java +++ b/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorRegistrationBuilderTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.*; import java.util.HashMap; +import java.util.List; import org.arkecosystem.crypto.transactions.types.Transaction; import org.junit.jupiter.api.Test; @@ -27,4 +28,28 @@ void build() { assertTrue(actual.verify()); } + + @Test + void buildMultiSignature() { + Transaction actual = + new ValidatorRegistrationBuilder() + .publicKeyAsset( + "a08058db53e2665c84a40f5152e76dd2b652125a6079130d4c315e728bcf4dd1dfb44ac26e82302331d61977d3141118") + .nonce(3) + .multiSign("secret 1", 0) + .multiSign("secret 2", 1) + .multiSign("secret 3", 2) + .sign("this is a top secret passphrase") + .transaction; + + assertTrue(actual.verify()); + + HashMap actualHashMap = actual.toHashMap(); + + assertNotNull(actualHashMap.get("signatures")); + + List actualSignatures = (List) actualHashMap.get("signatures"); + + assertEquals(3, actualSignatures.size()); + } } diff --git a/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorResignationBuilderTest.java b/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorResignationBuilderTest.java index b42b367f..960a93fa 100644 --- a/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorResignationBuilderTest.java +++ b/src/test/java/org/arkecosystem/crypto/transactions/builder/ValidatorResignationBuilderTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.*; import java.util.HashMap; +import java.util.List; import org.arkecosystem.crypto.transactions.types.Transaction; import org.junit.jupiter.api.Test; @@ -36,4 +37,26 @@ void buildSecondSignature() { actual.secondVerify( "03699e966b2525f9088a6941d8d94f7869964a000efe65783d78ac82e1199fe609")); } + + @Test + void buildMultiSignature() { + Transaction actual = + new ValidatorResignationBuilder() + .nonce(3) + .multiSign("secret 1", 0) + .multiSign("secret 2", 1) + .multiSign("secret 3", 2) + .sign("this is a top secret passphrase") + .transaction; + + assertTrue(actual.verify()); + + HashMap actualHashMap = actual.toHashMap(); + + assertNotNull(actualHashMap.get("signatures")); + + List actualSignatures = (List) actualHashMap.get("signatures"); + + assertEquals(3, actualSignatures.size()); + } } diff --git a/src/test/java/org/arkecosystem/crypto/transactions/builder/VoteBuilderTest.java b/src/test/java/org/arkecosystem/crypto/transactions/builder/VoteBuilderTest.java index 971773df..8aca1456 100644 --- a/src/test/java/org/arkecosystem/crypto/transactions/builder/VoteBuilderTest.java +++ b/src/test/java/org/arkecosystem/crypto/transactions/builder/VoteBuilderTest.java @@ -1,6 +1,7 @@ package org.arkecosystem.crypto.transactions.builder; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; @@ -128,4 +129,29 @@ void buildVoteSecondSignature() { actual.secondVerify( "03699e966b2525f9088a6941d8d94f7869964a000efe65783d78ac82e1199fe609")); } + + @Test + void buildMultiSignature() { + Transaction actual = + new VoteBuilder() + .addVote( + "034151a3ec46b5670a682b0a63394f863587d1bc97483b1b6c70eb58e7f0aed192") + .version(2) + .nonce(3) + .multiSign("secret 1", 0) + .multiSign("secret 2", 1) + .multiSign("secret 3", 2) + .sign("this is a top secret passphrase") + .transaction; + + assertTrue(actual.verify()); + + HashMap actualHashMap = actual.toHashMap(); + + assertNotNull(actualHashMap.get("signatures")); + + List actualSignatures = (List) actualHashMap.get("signatures"); + + assertEquals(3, actualSignatures.size()); + } } diff --git a/src/test/java/org/arkecosystem/crypto/transactions/deserializers/UsernameRegistrationTest.java b/src/test/java/org/arkecosystem/crypto/transactions/deserializers/UsernameRegistrationTest.java new file mode 100644 index 00000000..0853ed71 --- /dev/null +++ b/src/test/java/org/arkecosystem/crypto/transactions/deserializers/UsernameRegistrationTest.java @@ -0,0 +1,37 @@ +package org.arkecosystem.crypto.transactions.deserializers; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.google.gson.internal.LinkedTreeMap; +import org.arkecosystem.crypto.enums.TransactionTypeGroup; +import org.arkecosystem.crypto.transactions.Deserializer; +import org.arkecosystem.crypto.transactions.FixtureLoader; +import org.arkecosystem.crypto.transactions.types.Transaction; +import org.junit.jupiter.api.Test; + +public class UsernameRegistrationTest { + + @Test + void passphrase() { + LinkedTreeMap fixture = + FixtureLoader.load("transactions/username_registration/username-registration-sign"); + + LinkedTreeMap data = (LinkedTreeMap) fixture.get("data"); + + Transaction actual = new Deserializer(fixture.get("serialized").toString()).deserialize(); + + assertEquals(((Double) data.get("version")).intValue(), actual.version); + assertEquals(((Double) data.get("network")).intValue(), actual.network); + assertEquals(TransactionTypeGroup.CORE.getValue(), actual.typeGroup); + assertEquals(((Double) data.get("type")).intValue(), actual.type); + assertEquals((Long.valueOf((String) data.get("nonce"))), actual.nonce); + assertEquals(data.get("senderPublicKey").toString(), actual.senderPublicKey); + assertEquals((Long.valueOf((String) data.get("fee"))), actual.fee); + assertEquals(data.get("signature").toString(), actual.signature); + assertEquals(data.get("id").toString(), actual.id); + + LinkedTreeMap asset = (LinkedTreeMap) data.get("asset"); + + assertEquals((asset.get("username")), actual.asset.username); + } +} diff --git a/src/test/java/org/arkecosystem/crypto/transactions/deserializers/UsernameResignationTest.java b/src/test/java/org/arkecosystem/crypto/transactions/deserializers/UsernameResignationTest.java new file mode 100644 index 00000000..6dfa1ff7 --- /dev/null +++ b/src/test/java/org/arkecosystem/crypto/transactions/deserializers/UsernameResignationTest.java @@ -0,0 +1,36 @@ +package org.arkecosystem.crypto.transactions.deserializers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import com.google.gson.internal.LinkedTreeMap; +import org.arkecosystem.crypto.enums.TransactionTypeGroup; +import org.arkecosystem.crypto.transactions.Deserializer; +import org.arkecosystem.crypto.transactions.FixtureLoader; +import org.arkecosystem.crypto.transactions.types.Transaction; +import org.junit.jupiter.api.Test; + +class UsernameResignationTest { + + @Test + void passphrase() { + LinkedTreeMap fixture = + FixtureLoader.load("transactions/username_resignation/username-resignation-sign"); + + LinkedTreeMap data = (LinkedTreeMap) fixture.get("data"); + + Transaction actual = new Deserializer(fixture.get("serialized").toString()).deserialize(); + + assertEquals(((Double) data.get("version")).intValue(), actual.version); + assertEquals(((Double) data.get("network")).intValue(), actual.network); + assertEquals(TransactionTypeGroup.CORE.getValue(), actual.typeGroup); + assertEquals(((Double) data.get("type")).intValue(), actual.type); + assertEquals((Long.valueOf((String) data.get("nonce"))), actual.nonce); + assertEquals(data.get("senderPublicKey").toString(), actual.senderPublicKey); + assertEquals((Long.valueOf((String) data.get("fee"))), actual.fee); + assertEquals(data.get("signature").toString(), actual.signature); + assertEquals(data.get("id").toString(), actual.id); + + assertNull(data.get("asset")); + } +} diff --git a/src/test/java/org/arkecosystem/crypto/transactions/serializers/UsernameRegistrationTest.java b/src/test/java/org/arkecosystem/crypto/transactions/serializers/UsernameRegistrationTest.java new file mode 100644 index 00000000..c07191d6 --- /dev/null +++ b/src/test/java/org/arkecosystem/crypto/transactions/serializers/UsernameRegistrationTest.java @@ -0,0 +1,25 @@ +package org.arkecosystem.crypto.transactions.serializers; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.google.gson.internal.LinkedTreeMap; +import org.arkecosystem.crypto.encoding.Hex; +import org.arkecosystem.crypto.transactions.Deserializer; +import org.arkecosystem.crypto.transactions.FixtureLoader; +import org.arkecosystem.crypto.transactions.Serializer; +import org.arkecosystem.crypto.transactions.types.Transaction; +import org.junit.jupiter.api.Test; + +class UsernameRegistrationTest { + @Test + void passphrase() { + LinkedTreeMap fixture = + FixtureLoader.load("transactions/username_registration/username-registration-sign"); + Transaction transaction = + new Deserializer(fixture.get("serialized").toString()).deserialize(); + + String actual = Hex.encode(Serializer.serialize(transaction)); + + assertEquals(fixture.get("serialized").toString(), actual); + } +} diff --git a/src/test/java/org/arkecosystem/crypto/transactions/serializers/UsernameResignationTest.java b/src/test/java/org/arkecosystem/crypto/transactions/serializers/UsernameResignationTest.java new file mode 100644 index 00000000..ec77bef7 --- /dev/null +++ b/src/test/java/org/arkecosystem/crypto/transactions/serializers/UsernameResignationTest.java @@ -0,0 +1,26 @@ +package org.arkecosystem.crypto.transactions.serializers; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.google.gson.internal.LinkedTreeMap; +import org.arkecosystem.crypto.encoding.Hex; +import org.arkecosystem.crypto.transactions.Deserializer; +import org.arkecosystem.crypto.transactions.FixtureLoader; +import org.arkecosystem.crypto.transactions.Serializer; +import org.arkecosystem.crypto.transactions.types.Transaction; +import org.junit.jupiter.api.Test; + +class UsernameResignationTest { + @Test + void passphrase() { + LinkedTreeMap fixture = + FixtureLoader.load("transactions/username_resignation/username-resignation-sign"); + + Transaction transaction = + new Deserializer(fixture.get("serialized").toString()).deserialize(); + + String actual = Hex.encode(Serializer.serialize(transaction)); + + assertEquals(fixture.get("serialized").toString(), actual); + } +}