From b0448235b756ef5d2b205eb7ef35cd6ca224d983 Mon Sep 17 00:00:00 2001 From: meywood <105049338+meywood@users.noreply.github.com> Date: Mon, 15 Apr 2024 13:14:41 +0200 Subject: [PATCH 1/7] issues/263 - Initial import of com.syntifi.crypto codebase --- .../syntifi/crypto/key/ASN1Identifiers.java | 25 + .../crypto/key/AbstractPrivateKey.java | 83 + .../syntifi/crypto/key/AbstractPublicKey.java | 75 + .../syntifi/crypto/key/Ed25519PrivateKey.java | 121 + .../syntifi/crypto/key/Ed25519PublicKey.java | 85 + .../com/syntifi/crypto/key/PemFileHelper.java | 49 + .../crypto/key/Secp256k1PrivateKey.java | 129 ++ .../crypto/key/Secp256k1PublicKey.java | 109 + .../key/checksum/MixedCaseChecksum.java | 60 + .../HierarchicalDeterministicKey.java | 91 + .../com/syntifi/crypto/key/encdec/Base58.java | 163 ++ .../com/syntifi/crypto/key/encdec/Hex.java | 32 + .../com/syntifi/crypto/key/hash/Blake2b.java | 27 + .../syntifi/crypto/key/hash/Keccak256.java | 12 + .../com/syntifi/crypto/key/hash/Sha256.java | 27 + .../syntifi/crypto/key/mnemonic/Language.java | 51 + .../crypto/key/mnemonic/MnemonicCode.java | 285 +++ .../mnemonic/exception/MnemonicException.java | 65 + src/main/resources/chinese_simplified.txt | 2048 +++++++++++++++++ src/main/resources/chinese_traditional.txt | 2048 +++++++++++++++++ src/main/resources/english.txt | 2048 +++++++++++++++++ src/main/resources/french.txt | 2048 +++++++++++++++++ src/main/resources/portuguese.txt | 2048 +++++++++++++++++ src/main/resources/spanish.txt | 2048 +++++++++++++++++ .../crypto/key/AbstractCryptoTests.java | 72 + .../crypto/key/Ed25519PrivateKeyTests.java | 128 ++ .../crypto/key/Ed25519PublicKeyTests.java | 82 + .../crypto/key/Secp256k1PrivateKeyTests.java | 96 + .../crypto/key/Secp256k1PublicKeyTests.java | 63 + .../key/checksum/MixedCaseChecksumTest.java | 38 + .../HierarchicalDeterministicKeyTest.java | 45 + .../syntifi/crypto/key/encdec/Base58Test.java | 22 + .../syntifi/crypto/key/hash/Blake2bTest.java | 16 + .../crypto/key/hash/Keccak256Test.java | 14 + .../crypto/key/mnemonic/MnemonicCodeTest.java | 105 + src/test/resources/ed25519/public_key.pem | 3 + src/test/resources/ed25519/public_key_hex | 1 + src/test/resources/ed25519/secret_key.pem | 3 + src/test/resources/secp256k1/public_key.pem | 4 + src/test/resources/secp256k1/public_key_hex | 1 + src/test/resources/secp256k1/secret_key.pem | 3 + 41 files changed, 14473 insertions(+) create mode 100644 src/main/java/com/syntifi/crypto/key/ASN1Identifiers.java create mode 100644 src/main/java/com/syntifi/crypto/key/AbstractPrivateKey.java create mode 100644 src/main/java/com/syntifi/crypto/key/AbstractPublicKey.java create mode 100644 src/main/java/com/syntifi/crypto/key/Ed25519PrivateKey.java create mode 100644 src/main/java/com/syntifi/crypto/key/Ed25519PublicKey.java create mode 100644 src/main/java/com/syntifi/crypto/key/PemFileHelper.java create mode 100644 src/main/java/com/syntifi/crypto/key/Secp256k1PrivateKey.java create mode 100644 src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java create mode 100644 src/main/java/com/syntifi/crypto/key/checksum/MixedCaseChecksum.java create mode 100644 src/main/java/com/syntifi/crypto/key/deterministic/HierarchicalDeterministicKey.java create mode 100644 src/main/java/com/syntifi/crypto/key/encdec/Base58.java create mode 100644 src/main/java/com/syntifi/crypto/key/encdec/Hex.java create mode 100644 src/main/java/com/syntifi/crypto/key/hash/Blake2b.java create mode 100644 src/main/java/com/syntifi/crypto/key/hash/Keccak256.java create mode 100644 src/main/java/com/syntifi/crypto/key/hash/Sha256.java create mode 100644 src/main/java/com/syntifi/crypto/key/mnemonic/Language.java create mode 100644 src/main/java/com/syntifi/crypto/key/mnemonic/MnemonicCode.java create mode 100644 src/main/java/com/syntifi/crypto/key/mnemonic/exception/MnemonicException.java create mode 100644 src/main/resources/chinese_simplified.txt create mode 100644 src/main/resources/chinese_traditional.txt create mode 100644 src/main/resources/english.txt create mode 100644 src/main/resources/french.txt create mode 100644 src/main/resources/portuguese.txt create mode 100644 src/main/resources/spanish.txt create mode 100644 src/test/java/com/syntifi/crypto/key/AbstractCryptoTests.java create mode 100644 src/test/java/com/syntifi/crypto/key/Ed25519PrivateKeyTests.java create mode 100644 src/test/java/com/syntifi/crypto/key/Ed25519PublicKeyTests.java create mode 100644 src/test/java/com/syntifi/crypto/key/Secp256k1PrivateKeyTests.java create mode 100644 src/test/java/com/syntifi/crypto/key/Secp256k1PublicKeyTests.java create mode 100644 src/test/java/com/syntifi/crypto/key/checksum/MixedCaseChecksumTest.java create mode 100644 src/test/java/com/syntifi/crypto/key/deterministic/HierarchicalDeterministicKeyTest.java create mode 100644 src/test/java/com/syntifi/crypto/key/encdec/Base58Test.java create mode 100644 src/test/java/com/syntifi/crypto/key/hash/Blake2bTest.java create mode 100644 src/test/java/com/syntifi/crypto/key/hash/Keccak256Test.java create mode 100644 src/test/java/com/syntifi/crypto/key/mnemonic/MnemonicCodeTest.java create mode 100644 src/test/resources/ed25519/public_key.pem create mode 100644 src/test/resources/ed25519/public_key_hex create mode 100644 src/test/resources/ed25519/secret_key.pem create mode 100644 src/test/resources/secp256k1/public_key.pem create mode 100644 src/test/resources/secp256k1/public_key_hex create mode 100644 src/test/resources/secp256k1/secret_key.pem diff --git a/src/main/java/com/syntifi/crypto/key/ASN1Identifiers.java b/src/main/java/com/syntifi/crypto/key/ASN1Identifiers.java new file mode 100644 index 000000000..0753d149e --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/ASN1Identifiers.java @@ -0,0 +1,25 @@ +package com.syntifi.crypto.key; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +/** + * ASN1 identifiers for working with key cryptography + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.1.0 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ASN1Identifiers{ + + public static final ASN1ObjectIdentifier Secp256k1OIDCurve = new ASN1ObjectIdentifier("1.3.132.0.10"); + public static final ASN1ObjectIdentifier Secp256k1OIDkey = new ASN1ObjectIdentifier("1.2.840.10045.2.1"); + + public static final ASN1ObjectIdentifier Ed25519OID = new ASN1ObjectIdentifier("1.3.101.112"); + + public static final String PUBLIC_KEY_DER_HEADER = "PUBLIC KEY"; + public static final String PRIVATE_KEY_DER_HEADER = "PRIVATE KEY"; + public static final String EC_PRIVATE_KEY_DER_HEADER = "EC PRIVATE KEY"; +} \ No newline at end of file diff --git a/src/main/java/com/syntifi/crypto/key/AbstractPrivateKey.java b/src/main/java/com/syntifi/crypto/key/AbstractPrivateKey.java new file mode 100644 index 000000000..a059949bb --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/AbstractPrivateKey.java @@ -0,0 +1,83 @@ +package com.syntifi.crypto.key; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.security.GeneralSecurityException; + +/** + * Abstract class for needed shared functionalities + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.1.0 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public abstract class AbstractPrivateKey { + + private byte[] key; + + /** + * Loads a private key from a byte array + * + * @param privateKey the private key bytes + */ + public abstract void loadPrivateKey(final byte[] privateKey) throws IOException; + + /** + * Reads the private key from a file + * + * @param filename the source filename + * @throws IOException thrown if an error occurs reading the file + */ + public abstract void readPrivateKey(final String filename) throws IOException; + + /** + * Reads the private key from a stream + * + * @param reader the source of the private key + * @throws IOException thrown if an error occurs reading the file + */ + public abstract void readPrivateKey(final Reader reader) throws IOException; + + + /** + * Writes the private key to a file + * + * @param filename the target filename + * @throws IOException thrown if an error occurs writing the file + */ + public abstract void writePrivateKey(final String filename) throws IOException; + + /** + * Writes the private key to a file + * + * @param writer the target writer + * @throws IOException thrown if an error occurs writing the file + */ + + public abstract void writePrivateKey(final Writer writer) throws IOException; + + + /** + * Signs a message with the loaded key + * + * @param message message to sign + * @return signed message + * @throws GeneralSecurityException thrown if an error occurs processing message or signature + */ + public abstract byte[] sign(final byte[] message) throws GeneralSecurityException; + + /** + * Derives the public key from the loaded private key + * + * @return the derived {@link AbstractPublicKey} + */ + public abstract AbstractPublicKey derivePublicKey(); +} diff --git a/src/main/java/com/syntifi/crypto/key/AbstractPublicKey.java b/src/main/java/com/syntifi/crypto/key/AbstractPublicKey.java new file mode 100644 index 000000000..e8a5a6040 --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/AbstractPublicKey.java @@ -0,0 +1,75 @@ +package com.syntifi.crypto.key; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.security.GeneralSecurityException; + +/** + * Abstract class for needed shared functionalities + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.1.0 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public abstract class AbstractPublicKey { + + private byte[] key; + + /** + * Loads a public key from a byte array + * + * @param publicKey the public key bytes + */ + public abstract void loadPublicKey(final byte[] publicKey) throws IOException; + + /** + * Reads the public key from a file + * + * @param filename the source filename + * @throws IOException thrown if an error occurs reading the file + */ + public abstract void readPublicKey(final String filename) throws IOException; + + /** + * Reads the public key from a file + * + * @param reader the source filename + * @throws IOException thrown if an error occurs reading the file + */ + public abstract void readPublicKey(final Reader reader) throws IOException; + + + /** + * Writes the public key to a file + * + * @param filename the target filename + * @throws IOException thrown if an error occurs writing the file + */ + public abstract void writePublicKey(final String filename) throws IOException; + + /** + * Writes the public key to a file + * + * @param writer the target to write the public key + * @throws IOException thrown if an error occurs writing the file + */ + public abstract void writePublicKey(final Writer writer) throws IOException; + + /** + * Verifies message with given signature + * + * @param message the signed message + * @param signature the signature to check against + * @return true if matches, false otherwise + * @throws GeneralSecurityException thrown if an error occurs processing message and signature + */ + public abstract Boolean verify(final byte[] message, final byte[] signature) throws GeneralSecurityException; +} diff --git a/src/main/java/com/syntifi/crypto/key/Ed25519PrivateKey.java b/src/main/java/com/syntifi/crypto/key/Ed25519PrivateKey.java new file mode 100644 index 000000000..511fda299 --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/Ed25519PrivateKey.java @@ -0,0 +1,121 @@ +package com.syntifi.crypto.key; + +import com.syntifi.crypto.key.deterministic.HierarchicalDeterministicKey; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.bouncycastle.asn1.*; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.CryptoException; +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.Signer; +import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator; +import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters; +import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; +import org.bouncycastle.crypto.signers.Ed25519Signer; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; + +/** + * ed25519 implementation of {@link AbstractPrivateKey} + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.1.0 + */ +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class Ed25519PrivateKey extends AbstractPrivateKey { + + private Ed25519PrivateKeyParameters privateKeyParameters; + + public Ed25519PrivateKey(final byte[] privateKey) { + super(privateKey); + loadPrivateKey(privateKey); + } + + @Override + public void loadPrivateKey(final byte[] privateKey) { + privateKeyParameters = new Ed25519PrivateKeyParameters(privateKey, 0); + } + + /* + * SEQUENCE (3 elem) INTEGER 0 SEQUENCE (1 elem) OBJECT IDENTIFIER 1.3.101.112 + * curveEd25519 (EdDSA 25519 signature algorithm) OCTET STRING (32 byte) + * 38AECE974291F14B5FEF97E1B21F684394120B6E7A8AFB04398BBE787E8BC559 OCTET STRING + * (32 byte) 38AECE974291F14B5FEF97E1B21F684394120B6E7A8AFB04398BBE787E8BC559 + */ + @Override + public void readPrivateKey(final String filename) throws IOException { + try (final Reader fileReader = new FileReader(filename)) { + readPrivateKey(fileReader); + } + } + + @Override + public void readPrivateKey(final Reader reader) throws IOException { + final ASN1Primitive key = ASN1Primitive.fromByteArray(PemFileHelper.readPemFile(reader)); + final PrivateKeyInfo keyInfo = PrivateKeyInfo.getInstance(key); + final String algoId = keyInfo.getPrivateKeyAlgorithm().getAlgorithm().toString(); + if (algoId.equals(ASN1Identifiers.Ed25519OID.getId())) { + privateKeyParameters = new Ed25519PrivateKeyParameters(keyInfo.getPrivateKey().getEncoded(), 4); + setKey(privateKeyParameters.getEncoded()); + } + } + + @Override + public void writePrivateKey(final String filename) throws IOException { + try (final Writer fileWriter = new FileWriter(filename)) { + writePrivateKey(fileWriter); + } + } + + @Override + public void writePrivateKey(final Writer writer) throws IOException { + final DERSequence derPrefix = new DERSequence(ASN1Identifiers.Ed25519OID); + final DEROctetString key = new DEROctetString(new DEROctetString(getKey())); + final ASN1EncodableVector vector = new ASN1EncodableVector(); + vector.add(new ASN1Integer(0)); + vector.add(derPrefix); + vector.add(key); + final DERSequence derKey = new DERSequence(vector); + PemFileHelper.writePemFile(writer, derKey.getEncoded(), ASN1Identifiers.PRIVATE_KEY_DER_HEADER); + } + + @Override + public byte[] sign(final byte[] message) { + final Signer signer = new Ed25519Signer(); + signer.init(true, privateKeyParameters); + signer.update(message, 0, message.length); + byte[] signature; + try { + signature = signer.generateSignature(); + return signature; + } catch (DataLengthException | CryptoException e) { + // TODO: throw new SomeException(); + return null; + } + } + + @Override + public AbstractPublicKey derivePublicKey() { + return new Ed25519PublicKey(privateKeyParameters.generatePublicKey().getEncoded()); + } + + public static Ed25519PrivateKey deriveFromSeed(final byte[] seed, final int[] path) throws IOException { + final byte[] init = "ed25519 seed".getBytes(StandardCharsets.UTF_8); + final byte[] key = HierarchicalDeterministicKey.getFromSeed(seed, init, path); + return new Ed25519PrivateKey(key); + } + + public static Ed25519PrivateKey deriveRandomKey() { + final SecureRandom rnd = new SecureRandom(); + final Ed25519KeyPairGenerator keyPairGenerator = new Ed25519KeyPairGenerator(); + keyPairGenerator.init(new Ed25519KeyGenerationParameters(rnd)); + final AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair(); + final Ed25519PrivateKeyParameters privateKeyParameters = (Ed25519PrivateKeyParameters) asymmetricCipherKeyPair.getPrivate(); + return new Ed25519PrivateKey(privateKeyParameters.getEncoded()); + } +} diff --git a/src/main/java/com/syntifi/crypto/key/Ed25519PublicKey.java b/src/main/java/com/syntifi/crypto/key/Ed25519PublicKey.java new file mode 100644 index 000000000..430dcb5fd --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/Ed25519PublicKey.java @@ -0,0 +1,85 @@ +package com.syntifi.crypto.key; + +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.bouncycastle.asn1.*; +import org.bouncycastle.crypto.Signer; +import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +import org.bouncycastle.crypto.signers.Ed25519Signer; + +import java.io.*; + +/** + * ed25519 implementation of {@link AbstractPublicKey} + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.1.0 + */ +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class Ed25519PublicKey extends AbstractPublicKey { + + private Ed25519PublicKeyParameters publicKeyParameters; + + public Ed25519PublicKey(final byte[] publicKey) { + super(publicKey); + loadPublicKey(publicKey); + } + + @Override + public void loadPublicKey(final byte[] publicKey) { + publicKeyParameters = new Ed25519PublicKeyParameters(publicKey, 0); + } + + /* + * SEQUENCE (2 elem) SEQUENCE (1 elem) OBJECT IDENTIFIER 1.3.101.112 + * curveEd25519 (EdDSA 25519 signature algorithm) BIT STRING (256 bit) + */ + @Override + public void readPublicKey(final String filename) throws IOException { + try (final Reader fileReader = new FileReader(filename)) { + readPublicKey(fileReader); + } + } + + @Override + public void readPublicKey(final Reader reader) throws IOException { + final ASN1Primitive derKey = ASN1Primitive.fromByteArray(PemFileHelper.readPemFile(reader)); + final ASN1Sequence objBaseSeq = ASN1Sequence.getInstance(derKey); + final String objId = ASN1ObjectIdentifier + .getInstance(ASN1Sequence.getInstance(objBaseSeq.getObjectAt(0)).getObjectAt(0)).getId(); + if (objId.equals(ASN1Identifiers.Ed25519OID.getId())) { + final DERBitString key = DERBitString.getInstance(objBaseSeq.getObjectAt(1)); + publicKeyParameters = new Ed25519PublicKeyParameters(key.getBytes(), 0); + setKey(publicKeyParameters.getEncoded()); + } + } + + @Override + public void writePublicKey(final String filename) throws IOException { + try (final Writer fileWriter = new FileWriter(filename)) { + writePublicKey(fileWriter); + } + } + + @Override + public void writePublicKey(final Writer writer) throws IOException { + final DERSequence derPrefix = new DERSequence(ASN1Identifiers.Ed25519OID); + final DERBitString key = new DERBitString(getKey()); + final ASN1EncodableVector vector = new ASN1EncodableVector(); + vector.add(derPrefix); + vector.add(key); + final DERSequence derKey = new DERSequence(vector); + PemFileHelper.writePemFile(writer, derKey.getEncoded(), ASN1Identifiers.PUBLIC_KEY_DER_HEADER); + } + + @Override + public Boolean verify(final byte[] message, final byte[] signature) { + final Signer verifier = new Ed25519Signer(); + verifier.init(false, publicKeyParameters); + verifier.update(message, 0, message.length); + return verifier.verifySignature(signature); + } +} diff --git a/src/main/java/com/syntifi/crypto/key/PemFileHelper.java b/src/main/java/com/syntifi/crypto/key/PemFileHelper.java new file mode 100644 index 000000000..0308d87fc --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/PemFileHelper.java @@ -0,0 +1,49 @@ +package com.syntifi.crypto.key; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemReader; +import org.bouncycastle.util.io.pem.PemWriter; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; + +/** + * Helper methods for dealing with PEM files + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.1.0 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class PemFileHelper { + /** + * Reads a PEM file + * + * @param keyReader the reader to load the key from + * @return a byte array with file content + * @throws IOException thrown if error reading file + */ + public static byte[] readPemFile(final Reader keyReader) throws IOException { + try (final PemReader pemReader = new PemReader(keyReader)) { + final PemObject pemObject = pemReader.readPemObject(); + return pemObject.getContent(); + } + } + + /** + * Writes a PEM file + * + * @param fileWriter the writer of the key + * @param encodedKey the encoded key + * @param keyType the key type + * @throws IOException thrown if error writing file + */ + public static void writePemFile(final Writer fileWriter, final byte[] encodedKey, final String keyType) throws IOException { + try (final PemWriter pemWriter = new PemWriter(fileWriter)) { + pemWriter.writeObject(new PemObject(keyType, encodedKey)); + } + } +} diff --git a/src/main/java/com/syntifi/crypto/key/Secp256k1PrivateKey.java b/src/main/java/com/syntifi/crypto/key/Secp256k1PrivateKey.java new file mode 100644 index 000000000..8d0351a79 --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/Secp256k1PrivateKey.java @@ -0,0 +1,129 @@ +package com.syntifi.crypto.key; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.bouncycastle.asn1.*; +import org.web3j.crypto.ECKeyPair; +import org.web3j.crypto.Hash; +import org.web3j.crypto.Sign; +import org.web3j.crypto.Sign.SignatureData; + +import java.io.*; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.security.SecureRandom; + +/** + * secp256k1 implementation of {@link AbstractPrivateKey} + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.1.0 + */ +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class Secp256k1PrivateKey extends AbstractPrivateKey { + @Getter + @Setter + private ECKeyPair keyPair; + + public Secp256k1PrivateKey(final byte[] privateKey) throws IOException { + super(privateKey); + loadPrivateKey(privateKey); + } + + @Override + public void loadPrivateKey(final byte[] privateKey) throws IOException { + final ASN1Sequence key = (ASN1Sequence) ASN1Primitive.fromByteArray(privateKey); + final String algoId = key.getObjectAt(2).toString(); + if (algoId.equals("[0]" + ASN1Identifiers.Secp256k1OIDCurve) && key.getObjectAt(0).toString().equals("1")) { + final DEROctetString pk = (DEROctetString) key.getObjectAt(1); + keyPair = ECKeyPair.create(pk.getOctets()); + this.setKey(keyPair.getPrivateKey().toByteArray()); + } + } + + @Override + public void readPrivateKey(final String filename) throws IOException { + try (final Reader fileReader = new FileReader(filename)) { + readPrivateKey(fileReader); + } + } + + @Override + public void readPrivateKey(final Reader reader) throws IOException { + loadPrivateKey(PemFileHelper.readPemFile(reader)); + } + + @Override + public void writePrivateKey(final String filename) throws IOException { + try (final FileWriter fileWriter = new FileWriter(filename)) { + writePrivateKey(fileWriter); + } + } + + @Override + public void writePrivateKey(final Writer writer) throws IOException { + final DERTaggedObject derPrefix = new DERTaggedObject(0, ASN1Identifiers.Secp256k1OIDCurve); + final DEROctetString key = new DEROctetString(getKey()); + final ASN1EncodableVector vector = new ASN1EncodableVector(); + vector.add(new ASN1Integer(1)); + vector.add(key); + vector.add(derPrefix); + final DERSequence derKey = new DERSequence(vector); + PemFileHelper.writePemFile(writer, derKey.getEncoded(), ASN1Identifiers.EC_PRIVATE_KEY_DER_HEADER); + } + + /** + * When encoded in DER, this becomes the following sequence of bytes: + *

+ * 0x30 b1 0x02 b2 (vr) 0x02 b3 (vs) + *

+ * where: + *

+ * b1 is a single byte value, equal to the length, in bytes, of the remaining + * list of bytes (from the first 0x02 to the end of the encoding); + * b2 is a single byte value, equal to the length, in bytes, of (vr); + * b3 is a single byte value, equal to the length, in bytes, of (vs); + * (vr) is the signed big-endian encoding of the value "r + *

+ * ", of minimal length; + * (vs) is the signed big-endian encoding of the value "s + * ", of minimal length. + * + * @param message message to sign + * @return signed message + */ + @Override + public byte[] sign(final byte[] message) { + final SignatureData signature = Sign.signMessage(Hash.sha256(message), keyPair, false); + // TODO: Check this conversion + //return Hex.toHexString(signature.getR()) + Hex.toHexString(signature.getS()); + final ByteBuffer bb = ByteBuffer.allocate(signature.getR().length + signature.getS().length); + bb.put(signature.getR()); + bb.put(signature.getS()); + return bb.array(); + } + + /** + * Returns a Secp256k1PublicKey object in a compressed format + * adding the prefix 02/03 to identify the positive or negative Y followed + * by the X value in the elliptic curve + */ + @Override + public AbstractPublicKey derivePublicKey() { + final BigInteger pubKey = keyPair.getPublicKey(); + final byte[] pubKeyBytes = Secp256k1PublicKey.getShortKey(pubKey.toByteArray()); + return new Secp256k1PublicKey(pubKeyBytes); + } + + public static Secp256k1PrivateKey deriveRandomKey() { + final SecureRandom rnd = new SecureRandom(); + final ECKeyPair keyPair = ECKeyPair.create(rnd.generateSeed(32)); + final Secp256k1PrivateKey sk = new Secp256k1PrivateKey(); + sk.setKeyPair(keyPair); + return sk; + } +} diff --git a/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java b/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java new file mode 100644 index 000000000..12558360b --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java @@ -0,0 +1,109 @@ +package com.syntifi.crypto.key; + +import com.syntifi.crypto.key.encdec.Hex; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.bouncycastle.asn1.*; +import org.web3j.crypto.Hash; +import org.web3j.crypto.Sign; +import org.web3j.crypto.Sign.SignatureData; + +import java.io.*; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.util.Arrays; + +/** + * secp256k1 implementation of {@link AbstractPublicKey} + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.1.0 + */ +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class Secp256k1PublicKey extends AbstractPublicKey { + + public Secp256k1PublicKey(final byte[] bytes) { + super(bytes); + } + + @Override + public void loadPublicKey(final byte[] publicKey) throws IOException { + final ASN1Primitive derKey = ASN1Primitive.fromByteArray(publicKey); + final ASN1Sequence objBaseSeq = ASN1Sequence.getInstance(derKey); + final String keyId = ASN1ObjectIdentifier.getInstance(ASN1Sequence.getInstance(objBaseSeq.getObjectAt(0)).getObjectAt(0)).getId(); + final String curveId = ASN1ObjectIdentifier.getInstance(ASN1Sequence.getInstance(objBaseSeq.getObjectAt(0)).getObjectAt(1)).getId(); + if (curveId.equals(ASN1Identifiers.Secp256k1OIDCurve.getId()) + && keyId.equals(ASN1Identifiers.Secp256k1OIDkey.getId())) { + final DERBitString key = DERBitString.getInstance(objBaseSeq.getObjectAt(1)); + setKey(key.getBytes()); + } else { + throw new IOException(); + } + + } + + @Override + public void readPublicKey(final String filename) throws IOException { + try (final Reader fileReader = new FileReader(filename)) { + readPublicKey(fileReader); + } + } + + @Override + public void readPublicKey(final Reader reader) throws IOException { + loadPublicKey(PemFileHelper.readPemFile(reader)); + } + + @Override + public void writePublicKey(final String filename) throws IOException { + try (final FileWriter fileWriter = new FileWriter(filename)) { + writePublicKey(fileWriter); + } + } + + @Override + public void writePublicKey(final Writer writer) throws IOException { + final DERBitString key = new DERBitString(getKey()); + final ASN1EncodableVector v1 = new ASN1EncodableVector(); + v1.add(ASN1Identifiers.Secp256k1OIDkey); + v1.add(ASN1Identifiers.Secp256k1OIDCurve); + final DERSequence derPrefix = new DERSequence(v1); + final ASN1EncodableVector v2 = new ASN1EncodableVector(); + v2.add(derPrefix); + v2.add(key); + final DERSequence derKey = new DERSequence(v2); + PemFileHelper.writePemFile(writer, derKey.getEncoded(), ASN1Identifiers.PUBLIC_KEY_DER_HEADER); + } + + @Override + public Boolean verify(final byte[] message, final byte[] signature) throws GeneralSecurityException { + //TODO: Double check the issue the getV(), for now we are trying with both (27 and 28) + final SignatureData signatureData1 = new SignatureData( + (byte) 27, + Arrays.copyOfRange(signature, 0, 32), + Arrays.copyOfRange(signature, 32, 64)); + final BigInteger derivedKey1 = Sign.signedMessageHashToKey(Hash.sha256(message), signatureData1); + final SignatureData signatureData2 = new SignatureData( + (byte) 28, + Arrays.copyOfRange(signature, 0, 32), + Arrays.copyOfRange(signature, 32, 64)); + final BigInteger derivedKey2 = Sign.signedMessageHashToKey(Hash.sha256(message), signatureData2); + return Arrays.equals(Secp256k1PublicKey.getShortKey(derivedKey1.toByteArray()), getKey()) || + Arrays.equals(Secp256k1PublicKey.getShortKey(derivedKey2.toByteArray()), getKey()); + } + + /** + * Gets a short key + * + * @param key the key as a byte array + * @return short key as byte array + */ + public static byte[] getShortKey(final byte[] key) { + final BigInteger pubKey = new BigInteger(key); + final String pubKeyPrefix = pubKey.testBit(0) ? "03" : "02"; + final byte[] pubKeyBytes = Arrays.copyOfRange(key, 0, 32); + return Hex.decode(pubKeyPrefix + Hex.encode(pubKeyBytes)); + } +} diff --git a/src/main/java/com/syntifi/crypto/key/checksum/MixedCaseChecksum.java b/src/main/java/com/syntifi/crypto/key/checksum/MixedCaseChecksum.java new file mode 100644 index 000000000..2097ec710 --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/checksum/MixedCaseChecksum.java @@ -0,0 +1,60 @@ +package com.syntifi.crypto.key.checksum; + +import com.syntifi.crypto.key.encdec.Hex; +import com.syntifi.crypto.key.hash.Blake2b; +import com.syntifi.crypto.key.hash.Keccak256; + +/** + * Mixed checksumEncoding + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.5.0 + */ +public class MixedCaseChecksum { + + /** + * Implementation of the EIP-55: Mixed-case checksum address encoding + * Documentation available at: https://eips.ethereum.org/EIPS/eip-55 + * + * @param value Hex string + * @return + */ + public static String checksumEncodeEIP55(String value) { + char[] hash = Hex.encode(Keccak256.digest(value.toLowerCase().getBytes())).toCharArray(); + char[] chars = value.toCharArray(); + char[] encoded = new char[chars.length]; + for (int i = 0; i < chars.length; i++) { + encoded[i] = Character.digit(hash[i], 16) > 7 + ? Character.toUpperCase(chars[i]) + : Character.toLowerCase(chars[i]); + } + return String.valueOf(encoded); + } + + /** + * Implementation of the CEP-57 + * Documentation available at: https://github.com/casper-network/ceps/blob/master/text/0057-checksummed-addresses.md + * + * @param value Hex string + * @return + */ + public static String checksumEncodeCEP57(String value) { + byte[] hash = Blake2b.digest(Hex.decode(value), 32); + char[] chars = value.toCharArray(); + char[] encoded = new char[chars.length]; + int whichByte = 0; + int whichBit = 0; + for (int i = 0; i < chars.length; i++) { + boolean bitSet = (Byte.toUnsignedInt(hash[whichByte]) & (1< + * Note that this is not the same base58 as used by Flickr, which you may find referenced around the Internet. + *

+ * You may want to consider working with PrefixedChecksummedBytes instead, which + * adds support for testing the prefix and suffix bytes commonly found in addresses. + *

+ * Satoshi explains: why base-58 instead of standard base-64 encoding? + *

+ *

+ * However, note that the encoding/decoding runs in O(n²) time, so it is not useful for large data. + *

+ * The basic idea of the encoding is to treat the data bytes as a large number represented using + * base-256 digits, convert the number to be represented using base-58 digits, preserve the exact + * number of leading zeros (which are otherwise lost during the mathematical operations on the + * numbers), and finally represent the resulting base-58 digits as alphanumeric ASCII characters. + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.3.0 + */ +public final class Base58 { + public static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray(); + private static final char ENCODED_ZERO = ALPHABET[0]; + private static final int[] INDEXES = new int[128]; + + static { + Arrays.fill(INDEXES, -1); + for (int i = 0; i < ALPHABET.length; i++) { + INDEXES[ALPHABET[i]] = i; + } + } + + /** + * Encodes the given bytes as a base58 string (no checksum is appended). + * + * @param input the bytes to encode + * @return the base58-encoded string + */ + public static String encode(byte[] input) { + if (input.length == 0) { + return ""; + } + // Count leading zeros. + int zeros = 0; + while (zeros < input.length && input[zeros] == 0) { + ++zeros; + } + // Convert base-256 digits to base-58 digits (plus conversion to ASCII characters) + input = Arrays.copyOf(input, input.length); // since we modify it in-place + char[] encoded = new char[input.length * 2]; // upper bound + int outputStart = encoded.length; + for (int inputStart = zeros; inputStart < input.length; ) { + encoded[--outputStart] = ALPHABET[divmod(input, inputStart, 256, 58)]; + if (input[inputStart] == 0) { + ++inputStart; // optimization - skip leading zeros + } + } + // Preserve exactly as many leading encoded zeros in output as there were leading zeros in input. + while (outputStart < encoded.length && encoded[outputStart] == ENCODED_ZERO) { + ++outputStart; + } + while (--zeros >= 0) { + encoded[--outputStart] = ENCODED_ZERO; + } + // Return encoded string (including encoded leading zeros). + return new String(encoded, outputStart, encoded.length - outputStart); + } + + /** + * Decodes the given base58 string into the original data bytes. + * + * @param input the base58-encoded string to decode + * @return the decoded data bytes + * @throws RuntimeException if the given string is not a valid base58 string + */ + public static byte[] decode(String input) throws RuntimeException { + if (input.length() == 0) { + return new byte[0]; + } + // Convert the base58-encoded ASCII chars to a base58 byte sequence (base58 digits). + byte[] input58 = new byte[input.length()]; + for (int i = 0; i < input.length(); ++i) { + char c = input.charAt(i); + int digit = c < 128 ? INDEXES[c] : -1; + if (digit < 0) { + throw new RuntimeException(String.format("Invalid char %s at %s", c, i)); + } + input58[i] = (byte) digit; + } + // Count leading zeros. + int zeros = 0; + while (zeros < input58.length && input58[zeros] == 0) { + ++zeros; + } + // Convert base-58 digits to base-256 digits. + byte[] decoded = new byte[input.length()]; + int outputStart = decoded.length; + for (int inputStart = zeros; inputStart < input58.length; ) { + decoded[--outputStart] = divmod(input58, inputStart, 58, 256); + if (input58[inputStart] == 0) { + ++inputStart; // optimization - skip leading zeros + } + } + // Ignore extra leading zeroes that were added during the calculation. + while (outputStart < decoded.length && decoded[outputStart] == 0) { + ++outputStart; + } + // Return decoded data (including original number of leading zeros). + return Arrays.copyOfRange(decoded, outputStart - zeros, decoded.length); + } + + /** + * Divides a number, represented as an array of bytes each containing a single digit + * in the specified base, by the given divisor. The given number is modified in-place + * to contain the quotient, and the return value is the remainder. + * + * @param number the number to divide + * @param firstDigit the index within the array of the first non-zero digit + * (this is used for optimization by skipping the leading zeros) + * @param base the base in which the number's digits are represented (up to 256) + * @param divisor the number to divide by (up to 256) + * @return the remainder of the division operation + */ + private static byte divmod(byte[] number, int firstDigit, int base, int divisor) { + // this is just long division which accounts for the base of the input digits + int remainder = 0; + for (int i = firstDigit; i < number.length; i++) { + int digit = (int) number[i] & 0xFF; + int temp = remainder * base + digit; + number[i] = (byte) (temp / divisor); + remainder = temp % divisor; + } + return (byte) remainder; + } +} \ No newline at end of file diff --git a/src/main/java/com/syntifi/crypto/key/encdec/Hex.java b/src/main/java/com/syntifi/crypto/key/encdec/Hex.java new file mode 100644 index 000000000..e8262d2c9 --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/encdec/Hex.java @@ -0,0 +1,32 @@ +package com.syntifi.crypto.key.encdec; + +/** + * Hex encoder/decoder + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.3.0 + */ +public class Hex { + + /** + * Byte array encoder + * + * @param bytes byte array + * @return Hex String + */ + public static String encode(byte[] bytes) { + return org.bouncycastle.util.encoders.Hex.toHexString(bytes); + } + + /** + * Hex string decoder + * + * @param hex Hex string + * @return byte array + */ + public static byte[] decode(String hex) { + return org.bouncycastle.util.encoders.Hex.decode(hex); + } + +} diff --git a/src/main/java/com/syntifi/crypto/key/hash/Blake2b.java b/src/main/java/com/syntifi/crypto/key/hash/Blake2b.java new file mode 100644 index 000000000..51faf7185 --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/hash/Blake2b.java @@ -0,0 +1,27 @@ +package com.syntifi.crypto.key.hash; + +import org.bouncycastle.crypto.digests.Blake2bDigest; + +/** + * Blake2 Hash helper class + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.2.0 + */ +public class Blake2b { + /** + * returns a Blake2b Hash of size length in bytes + * + * @param input byte array to hash + * @param length desired output length in bytes + * @return a byte array of size 'length' bytes + */ + public static byte[] digest(byte[] input, int length) { + Blake2bDigest d = new Blake2bDigest(length * 8); + d.update(input, 0, input.length); + byte[] result = new byte[d.getDigestSize()]; + d.doFinal(result, 0); + return result; + } +} diff --git a/src/main/java/com/syntifi/crypto/key/hash/Keccak256.java b/src/main/java/com/syntifi/crypto/key/hash/Keccak256.java new file mode 100644 index 000000000..8baa147c7 --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/hash/Keccak256.java @@ -0,0 +1,12 @@ +package com.syntifi.crypto.key.hash; + +import org.bouncycastle.jcajce.provider.digest.Keccak; + +public class Keccak256 { + + public static byte[] digest(byte[] value) { + Keccak.DigestKeccak kekkac256 = new Keccak.Digest256(); + byte[] hash = kekkac256.digest(value); + return hash; + } +} diff --git a/src/main/java/com/syntifi/crypto/key/hash/Sha256.java b/src/main/java/com/syntifi/crypto/key/hash/Sha256.java new file mode 100644 index 000000000..91f77f24e --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/hash/Sha256.java @@ -0,0 +1,27 @@ +package com.syntifi.crypto.key.hash; + +import org.bouncycastle.crypto.digests.SHA256Digest; + +/** + * Sha256 Hash helper class + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.2.0 + */ +public final class Sha256 { + + /** + * returns a Sha 256 Hash of size length in bytes + * + * @param input byte array to hash + * @return a byte array of size 'length' bytes + */ + public static byte[] digest(byte[] input) { + SHA256Digest d = new SHA256Digest(); + d.update(input, 0, input.length); + byte[] result = new byte[d.getDigestSize()]; + d.doFinal(result, 0); + return result; + } +} diff --git a/src/main/java/com/syntifi/crypto/key/mnemonic/Language.java b/src/main/java/com/syntifi/crypto/key/mnemonic/Language.java new file mode 100644 index 000000000..4fa0900b0 --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/mnemonic/Language.java @@ -0,0 +1,51 @@ +package com.syntifi.crypto.key.mnemonic; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Locale; + +/** + * Enum with the languages, dictionaries and checkSum supported for Mnemonic generation + * Abstract class for needed shared functionalities + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.3.0 + */ +public enum Language { + EN("english.txt", "ad90bf3beb7b0eb7e5acd74727dc0da96e0a280a258354e7293fb7e211ac03db", StandardCharsets.UTF_8, Locale.ENGLISH), + PT("portuguese.txt", "eed387d44cf8f32f60754527e265230d8019e8a2277937c71ef812e7a46c93fd", StandardCharsets.UTF_8, Locale.forLanguageTag("PT")), + ES("spanish.txt", "a556a26c6a5bb36db0fb7d8bf579cb7465fcaeec03957c0dda61b569962d9da5", StandardCharsets.UTF_8, Locale.forLanguageTag("ES")), + FR("french.txt", "9cbdaadbd3ce9cbaee1b360fce45e935b21e3e2c56d9fcd56b3398ced2371866", StandardCharsets.UTF_8, Locale.FRENCH), + CNS("chinese_simplified.txt", "bfd683b91db88609fabad8968c7efe4bf69606bf5a49ac4a4ba5e355955670cb", StandardCharsets.UTF_8, Locale.CHINA), + CNT("chinese_traditional.txt", "", StandardCharsets.UTF_8, Locale.CHINESE); + + private final String fileName; + private final String checkSum; + private final Charset charset; + private final Locale locale; + + Language(String fileName, String checkSum, Charset charset, Locale locale) { + this.fileName = fileName; + this.checkSum = checkSum; + this.charset = charset; + this.locale = locale; + } + + + public String getFileName() { + return fileName; + } + + public String getCheckSum() { + return checkSum; + } + + public Charset getCharset() { + return charset; + } + + public Locale getLocale() { + return locale; + } +} diff --git a/src/main/java/com/syntifi/crypto/key/mnemonic/MnemonicCode.java b/src/main/java/com/syntifi/crypto/key/mnemonic/MnemonicCode.java new file mode 100644 index 000000000..48a28d50b --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/mnemonic/MnemonicCode.java @@ -0,0 +1,285 @@ +package com.syntifi.crypto.key.mnemonic; + +/* + * Copyright 2013 Ken Sedgwick + * Copyright 2014 Andreas Schildbach + * + * 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. + * + * CHANGES: + * - Removing static initializer + * - Using own Hex and Sha256 implementations + * - Removing logs, watches, ... + * - Removing internal dependencies to helper/utils + * - Adding method to secure random derive the key + * - Adding support for multiple languages + * + */ + +import com.syntifi.crypto.key.encdec.Hex; +import com.syntifi.crypto.key.hash.Sha256; +import com.syntifi.crypto.key.mnemonic.exception.MnemonicException; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; +import org.bouncycastle.crypto.params.KeyParameter; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * A MnemonicCode object may be used to convert between binary seed values and + * lists of words per the BIP 39 + * specification + * Original implementation at: + * https://github.com/bitcoinj/bitcoinj/blob/master/core/src/main/java/org/bitcoinj/crypto/MnemonicCode.java + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.3.0 + */ +public class MnemonicCode { + private static final int PBKDF2_ROUNDS = 2048; + private final List wordList; + private final Language language; + + /** + * Creates an MnemonicCode object, initializing with words read from the supplied input stream. + * If a wordListDigest is supplied the digest of the words will be checked. + * + * @param language words languages + * @throws IOException if an error ocrurs when processing the file buffers + */ + public MnemonicCode(Language language) throws IOException { + this.language = language; + InputStream wordStream = getClass().getResourceAsStream("/" + language.getFileName()); + if (wordStream == null) + throw new FileNotFoundException(language.getFileName()); + try (BufferedReader br = new BufferedReader(new InputStreamReader(wordStream, language.getCharset()))) { + this.wordList = br.lines() + .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); + } + + if (this.wordList.size() != 2048) + throw new IllegalArgumentException("input stream did not contain 2048 bytes"); + + // If a wordListDigest is supplied check to make sure it matches. + if (language.getCheckSum()!= null) { + StringBuilder stringBuilder = new StringBuilder(); + for (String s : this.getWordList()) { + stringBuilder.append(s); + } + byte[] digest = Sha256.digest(String.valueOf(stringBuilder).getBytes(language.getCharset())); + String hexDigest = Hex.encode(digest); + if (!hexDigest.equals(language.getCheckSum())) + throw new IllegalArgumentException("wordlist checksum mismatch"); + } + } + + /** + * Convert mnemonic word list to seed. + * + * @param words list of words + * @return derived seed in byte array + */ + public byte[] toSeed(List words) { + return toSeed(words, ""); + } + + /** + * Convert mnemonic word list to seed. + * + * @param words list of words + * @param passphrase password, use {@link #toSeed(List)} if not required + * @return derived seed in byte array + */ + public byte[] toSeed(List words, String passphrase) { + if (passphrase == null) + throw new RuntimeException("A null passphrase is not allowed."); + + // To create binary seed from mnemonic, we use PBKDF2 function + // with mnemonic sentence (in UTF-8) used as a password and + // string "mnemonic" + passphrase (again in UTF-8) used as a + // salt. Iteration count is set to 2048 and HMAC-SHA512 is + // used as a pseudo-random function. Desired length of the + // derived key is 512 bits (= 64 bytes). + // + String pass = String.join(" ", words); + String salt = "mnemonic" + passphrase; + + final PKCS5S2ParametersGenerator pbkdf2 = new PKCS5S2ParametersGenerator(new SHA512Digest()); + pbkdf2.init( + pass.getBytes(StandardCharsets.UTF_8), + salt.getBytes(StandardCharsets.UTF_8), + PBKDF2_ROUNDS); + + final KeyParameter key = (KeyParameter) pbkdf2.generateDerivedParameters(512); + return key.getKey(); + } + + private boolean[] bytesToBits(byte[] data) { + boolean[] bits = new boolean[data.length * 8]; + for (int i = 0; i < data.length; ++i) + for (int j = 0; j < 8; ++j) + bits[(i * 8) + j] = (data[i] & (1 << (7 - j))) != 0; + return bits; + } + + + /** + * Gets the word list this code uses. + * + * @return unmodifiable word list + */ + public List getWordList() { + return wordList; + } + + /** + * Convert mnemonic word list to original entropy value. + * + * @param words list of words + * @return entropy byte array + * @throws MnemonicException.MnemonicLengthException if the number of words in the list is not multiple of 3 or empty + * @throws MnemonicException.MnemonicWordException if a word in the list is not part of the dictionary + * @throws MnemonicException.MnemonicChecksumException if the checksum of the file does not match the specified one + */ + public byte[] toEntropy(List words) throws MnemonicException.MnemonicLengthException, + MnemonicException.MnemonicWordException, MnemonicException.MnemonicChecksumException { + if (words.size() % 3 > 0) + throw new MnemonicException.MnemonicLengthException("Word list size must be multiple of three words."); + + if (words.size() == 0) + throw new MnemonicException.MnemonicLengthException("Word list is empty."); + + // Look up all the words in the list and construct the + // concatenation of the original entropy and the checksum. + // + int concatLenBits = words.size() * 11; + boolean[] concatBits = new boolean[concatLenBits]; + int wordindex = 0; + Collator collator = Collator.getInstance(language.getLocale()); + //collator.setDecomposition(Collator.FULL_DECOMPOSITION); + //collator.setStrength(Collator.PRIMARY); + for (String word : words) { + // Find the words index in the wordlist. + int ndx = Collections.binarySearch(this.wordList, word, collator); + if (ndx < 0) + throw new MnemonicException.MnemonicWordException(word); + + // Set the next 11 bits to the value of the index. + for (int ii = 0; ii < 11; ++ii) + concatBits[(wordindex * 11) + ii] = (ndx & (1 << (10 - ii))) != 0; + ++wordindex; + } + + int checksumLengthBits = concatLenBits / 33; + int entropyLengthBits = concatLenBits - checksumLengthBits; + + // Extract original entropy as bytes. + byte[] entropy = new byte[entropyLengthBits / 8]; + for (int ii = 0; ii < entropy.length; ++ii) + for (int jj = 0; jj < 8; ++jj) + if (concatBits[(ii * 8) + jj]) + entropy[ii] |= 1 << (7 - jj); + + // Take the digest of the entropy. + byte[] hash = Sha256.digest(entropy); + boolean[] hashBits = bytesToBits(hash); + + // Check all the checksum bits. + for (int i = 0; i < checksumLengthBits; ++i) + if (concatBits[entropyLengthBits + i] != hashBits[i]) + throw new MnemonicException.MnemonicChecksumException(); + + return entropy; + } + + /** + * Convert entropy data to mnemonic word list. + * + * @param entropy byte array + * @return list of words + * @throws MnemonicException.MnemonicLengthException if the number of words in the list is not multiple of 3 or empty + */ + public List toMnemonic(byte[] entropy) throws MnemonicException.MnemonicLengthException { + if (entropy.length % 4 > 0) + throw new MnemonicException.MnemonicLengthException("Entropy length not multiple of 32 bits."); + + if (entropy.length == 0) + throw new MnemonicException.MnemonicLengthException("Entropy is empty."); + + // We take initial entropy of ENT bits and compute its + // checksum by taking first ENT / 32 bits of its SHA256 hash. + + byte[] hash = Sha256.digest(entropy); + boolean[] hashBits = bytesToBits(hash); + + boolean[] entropyBits = bytesToBits(entropy); + int checksumLengthBits = entropyBits.length / 32; + + // We append these bits to the end of the initial entropy. + boolean[] concatBits = new boolean[entropyBits.length + checksumLengthBits]; + System.arraycopy(entropyBits, 0, concatBits, 0, entropyBits.length); + System.arraycopy(hashBits, 0, concatBits, entropyBits.length, checksumLengthBits); + + // Next we take these concatenated bits and split them into + // groups of 11 bits. Each group encodes number from 0-2047 + // which is a position in a wordlist. We convert numbers into + // words and use joined words as mnemonic sentence. + + ArrayList words = new ArrayList<>(); + int nWords = concatBits.length / 11; + for (int i = 0; i < nWords; ++i) { + int index = 0; + for (int j = 0; j < 11; ++j) { + index <<= 1; + if (concatBits[(i * 11) + j]) + index |= 0x1; + } + words.add(this.wordList.get(index)); + } + + return words; + } + + /** + * Check to see if a mnemonic word list is valid. + * + * @param words list of words + * @throws MnemonicException if an errors occurs on reading the dictionary of on the given words + */ + public void check(List words) throws MnemonicException { + toEntropy(words); + } + + /** + * Method to generate words from securerandom entropy + * + * @return list of mnemonic words + * @throws IOException if an error occurs in reading the dictionary file + * @throws MnemonicException.MnemonicLengthException if the number of words in the list is not multiple of 3 or empty + */ + public List generateSecureRandomWords() throws IOException, MnemonicException.MnemonicLengthException { + MnemonicCode mnemonicCode = new MnemonicCode(this.language); + SecureRandom rnd = new SecureRandom(); + byte[] entropy = new byte[16]; + rnd.nextBytes(entropy); + return mnemonicCode.toMnemonic(entropy); + } +} diff --git a/src/main/java/com/syntifi/crypto/key/mnemonic/exception/MnemonicException.java b/src/main/java/com/syntifi/crypto/key/mnemonic/exception/MnemonicException.java new file mode 100644 index 000000000..0a969cf58 --- /dev/null +++ b/src/main/java/com/syntifi/crypto/key/mnemonic/exception/MnemonicException.java @@ -0,0 +1,65 @@ +package com.syntifi.crypto.key.mnemonic.exception; +/* + * Copyright 2013 Ken Sedgwick + * + * 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. + */ + + +/** + * Exceptions thrown by the MnemonicCode module. + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.3.0 + */ +public class MnemonicException extends Exception { + public MnemonicException() { + super(); + } + + public MnemonicException(String msg) { + super(msg); + } + + /** + * Thrown when an argument to MnemonicCode is the wrong length. + */ + public static class MnemonicLengthException extends MnemonicException { + public MnemonicLengthException(String msg) { + super(msg); + } + } + + /** + * Thrown when a list of MnemonicCode words fails the checksum check. + */ + public static class MnemonicChecksumException extends MnemonicException { + public MnemonicChecksumException() { + super(); + } + } + + /** + * Thrown when a word is encountered which is not in the MnemonicCode's word list. + */ + public static class MnemonicWordException extends MnemonicException { + /** Contains the word that was not found in the word list. */ + public final String badWord; + + public MnemonicWordException(String badWord) { + super(); + this.badWord = badWord; + } + } +} \ No newline at end of file diff --git a/src/main/resources/chinese_simplified.txt b/src/main/resources/chinese_simplified.txt new file mode 100644 index 000000000..b90f1ed85 --- /dev/null +++ b/src/main/resources/chinese_simplified.txt @@ -0,0 +1,2048 @@ +的 +一 +是 +在 +不 +了 +有 +和 +人 +这 +中 +大 +为 +上 +个 +国 +我 +以 +要 +他 +时 +来 +用 +们 +生 +到 +作 +地 +于 +出 +就 +分 +对 +成 +会 +可 +主 +发 +年 +动 +同 +工 +也 +能 +下 +过 +子 +说 +产 +种 +面 +而 +方 +后 +多 +定 +行 +学 +法 +所 +民 +得 +经 +十 +三 +之 +进 +着 +等 +部 +度 +家 +电 +力 +里 +如 +水 +化 +高 +自 +二 +理 +起 +小 +物 +现 +实 +加 +量 +都 +两 +体 +制 +机 +当 +使 +点 +从 +业 +本 +去 +把 +性 +好 +应 +开 +它 +合 +还 +因 +由 +其 +些 +然 +前 +外 +天 +政 +四 +日 +那 +社 +义 +事 +平 +形 +相 +全 +表 +间 +样 +与 +关 +各 +重 +新 +线 +内 +数 +正 +心 +反 +你 +明 +看 +原 +又 +么 +利 +比 +或 +但 +质 +气 +第 +向 +道 +命 +此 +变 +条 +只 +没 +结 +解 +问 +意 +建 +月 +公 +无 +系 +军 +很 +情 +者 +最 +立 +代 +想 +已 +通 +并 +提 +直 +题 +党 +程 +展 +五 +果 +料 +象 +员 +革 +位 +入 +常 +文 +总 +次 +品 +式 +活 +设 +及 +管 +特 +件 +长 +求 +老 +头 +基 +资 +边 +流 +路 +级 +少 +图 +山 +统 +接 +知 +较 +将 +组 +见 +计 +别 +她 +手 +角 +期 +根 +论 +运 +农 +指 +几 +九 +区 +强 +放 +决 +西 +被 +干 +做 +必 +战 +先 +回 +则 +任 +取 +据 +处 +队 +南 +给 +色 +光 +门 +即 +保 +治 +北 +造 +百 +规 +热 +领 +七 +海 +口 +东 +导 +器 +压 +志 +世 +金 +增 +争 +济 +阶 +油 +思 +术 +极 +交 +受 +联 +什 +认 +六 +共 +权 +收 +证 +改 +清 +美 +再 +采 +转 +更 +单 +风 +切 +打 +白 +教 +速 +花 +带 +安 +场 +身 +车 +例 +真 +务 +具 +万 +每 +目 +至 +达 +走 +积 +示 +议 +声 +报 +斗 +完 +类 +八 +离 +华 +名 +确 +才 +科 +张 +信 +马 +节 +话 +米 +整 +空 +元 +况 +今 +集 +温 +传 +土 +许 +步 +群 +广 +石 +记 +需 +段 +研 +界 +拉 +林 +律 +叫 +且 +究 +观 +越 +织 +装 +影 +算 +低 +持 +音 +众 +书 +布 +复 +容 +儿 +须 +际 +商 +非 +验 +连 +断 +深 +难 +近 +矿 +千 +周 +委 +素 +技 +备 +半 +办 +青 +省 +列 +习 +响 +约 +支 +般 +史 +感 +劳 +便 +团 +往 +酸 +历 +市 +克 +何 +除 +消 +构 +府 +称 +太 +准 +精 +值 +号 +率 +族 +维 +划 +选 +标 +写 +存 +候 +毛 +亲 +快 +效 +斯 +院 +查 +江 +型 +眼 +王 +按 +格 +养 +易 +置 +派 +层 +片 +始 +却 +专 +状 +育 +厂 +京 +识 +适 +属 +圆 +包 +火 +住 +调 +满 +县 +局 +照 +参 +红 +细 +引 +听 +该 +铁 +价 +严 +首 +底 +液 +官 +德 +随 +病 +苏 +失 +尔 +死 +讲 +配 +女 +黄 +推 +显 +谈 +罪 +神 +艺 +呢 +席 +含 +企 +望 +密 +批 +营 +项 +防 +举 +球 +英 +氧 +势 +告 +李 +台 +落 +木 +帮 +轮 +破 +亚 +师 +围 +注 +远 +字 +材 +排 +供 +河 +态 +封 +另 +施 +减 +树 +溶 +怎 +止 +案 +言 +士 +均 +武 +固 +叶 +鱼 +波 +视 +仅 +费 +紧 +爱 +左 +章 +早 +朝 +害 +续 +轻 +服 +试 +食 +充 +兵 +源 +判 +护 +司 +足 +某 +练 +差 +致 +板 +田 +降 +黑 +犯 +负 +击 +范 +继 +兴 +似 +余 +坚 +曲 +输 +修 +故 +城 +夫 +够 +送 +笔 +船 +占 +右 +财 +吃 +富 +春 +职 +觉 +汉 +画 +功 +巴 +跟 +虽 +杂 +飞 +检 +吸 +助 +升 +阳 +互 +初 +创 +抗 +考 +投 +坏 +策 +古 +径 +换 +未 +跑 +留 +钢 +曾 +端 +责 +站 +简 +述 +钱 +副 +尽 +帝 +射 +草 +冲 +承 +独 +令 +限 +阿 +宣 +环 +双 +请 +超 +微 +让 +控 +州 +良 +轴 +找 +否 +纪 +益 +依 +优 +顶 +础 +载 +倒 +房 +突 +坐 +粉 +敌 +略 +客 +袁 +冷 +胜 +绝 +析 +块 +剂 +测 +丝 +协 +诉 +念 +陈 +仍 +罗 +盐 +友 +洋 +错 +苦 +夜 +刑 +移 +频 +逐 +靠 +混 +母 +短 +皮 +终 +聚 +汽 +村 +云 +哪 +既 +距 +卫 +停 +烈 +央 +察 +烧 +迅 +境 +若 +印 +洲 +刻 +括 +激 +孔 +搞 +甚 +室 +待 +核 +校 +散 +侵 +吧 +甲 +游 +久 +菜 +味 +旧 +模 +湖 +货 +损 +预 +阻 +毫 +普 +稳 +乙 +妈 +植 +息 +扩 +银 +语 +挥 +酒 +守 +拿 +序 +纸 +医 +缺 +雨 +吗 +针 +刘 +啊 +急 +唱 +误 +训 +愿 +审 +附 +获 +茶 +鲜 +粮 +斤 +孩 +脱 +硫 +肥 +善 +龙 +演 +父 +渐 +血 +欢 +械 +掌 +歌 +沙 +刚 +攻 +谓 +盾 +讨 +晚 +粒 +乱 +燃 +矛 +乎 +杀 +药 +宁 +鲁 +贵 +钟 +煤 +读 +班 +伯 +香 +介 +迫 +句 +丰 +培 +握 +兰 +担 +弦 +蛋 +沉 +假 +穿 +执 +答 +乐 +谁 +顺 +烟 +缩 +征 +脸 +喜 +松 +脚 +困 +异 +免 +背 +星 +福 +买 +染 +井 +概 +慢 +怕 +磁 +倍 +祖 +皇 +促 +静 +补 +评 +翻 +肉 +践 +尼 +衣 +宽 +扬 +棉 +希 +伤 +操 +垂 +秋 +宜 +氢 +套 +督 +振 +架 +亮 +末 +宪 +庆 +编 +牛 +触 +映 +雷 +销 +诗 +座 +居 +抓 +裂 +胞 +呼 +娘 +景 +威 +绿 +晶 +厚 +盟 +衡 +鸡 +孙 +延 +危 +胶 +屋 +乡 +临 +陆 +顾 +掉 +呀 +灯 +岁 +措 +束 +耐 +剧 +玉 +赵 +跳 +哥 +季 +课 +凯 +胡 +额 +款 +绍 +卷 +齐 +伟 +蒸 +殖 +永 +宗 +苗 +川 +炉 +岩 +弱 +零 +杨 +奏 +沿 +露 +杆 +探 +滑 +镇 +饭 +浓 +航 +怀 +赶 +库 +夺 +伊 +灵 +税 +途 +灭 +赛 +归 +召 +鼓 +播 +盘 +裁 +险 +康 +唯 +录 +菌 +纯 +借 +糖 +盖 +横 +符 +私 +努 +堂 +域 +枪 +润 +幅 +哈 +竟 +熟 +虫 +泽 +脑 +壤 +碳 +欧 +遍 +侧 +寨 +敢 +彻 +虑 +斜 +薄 +庭 +纳 +弹 +饲 +伸 +折 +麦 +湿 +暗 +荷 +瓦 +塞 +床 +筑 +恶 +户 +访 +塔 +奇 +透 +梁 +刀 +旋 +迹 +卡 +氯 +遇 +份 +毒 +泥 +退 +洗 +摆 +灰 +彩 +卖 +耗 +夏 +择 +忙 +铜 +献 +硬 +予 +繁 +圈 +雪 +函 +亦 +抽 +篇 +阵 +阴 +丁 +尺 +追 +堆 +雄 +迎 +泛 +爸 +楼 +避 +谋 +吨 +野 +猪 +旗 +累 +偏 +典 +馆 +索 +秦 +脂 +潮 +爷 +豆 +忽 +托 +惊 +塑 +遗 +愈 +朱 +替 +纤 +粗 +倾 +尚 +痛 +楚 +谢 +奋 +购 +磨 +君 +池 +旁 +碎 +骨 +监 +捕 +弟 +暴 +割 +贯 +殊 +释 +词 +亡 +壁 +顿 +宝 +午 +尘 +闻 +揭 +炮 +残 +冬 +桥 +妇 +警 +综 +招 +吴 +付 +浮 +遭 +徐 +您 +摇 +谷 +赞 +箱 +隔 +订 +男 +吹 +园 +纷 +唐 +败 +宋 +玻 +巨 +耕 +坦 +荣 +闭 +湾 +键 +凡 +驻 +锅 +救 +恩 +剥 +凝 +碱 +齿 +截 +炼 +麻 +纺 +禁 +废 +盛 +版 +缓 +净 +睛 +昌 +婚 +涉 +筒 +嘴 +插 +岸 +朗 +庄 +街 +藏 +姑 +贸 +腐 +奴 +啦 +惯 +乘 +伙 +恢 +匀 +纱 +扎 +辩 +耳 +彪 +臣 +亿 +璃 +抵 +脉 +秀 +萨 +俄 +网 +舞 +店 +喷 +纵 +寸 +汗 +挂 +洪 +贺 +闪 +柬 +爆 +烯 +津 +稻 +墙 +软 +勇 +像 +滚 +厘 +蒙 +芳 +肯 +坡 +柱 +荡 +腿 +仪 +旅 +尾 +轧 +冰 +贡 +登 +黎 +削 +钻 +勒 +逃 +障 +氨 +郭 +峰 +币 +港 +伏 +轨 +亩 +毕 +擦 +莫 +刺 +浪 +秘 +援 +株 +健 +售 +股 +岛 +甘 +泡 +睡 +童 +铸 +汤 +阀 +休 +汇 +舍 +牧 +绕 +炸 +哲 +磷 +绩 +朋 +淡 +尖 +启 +陷 +柴 +呈 +徒 +颜 +泪 +稍 +忘 +泵 +蓝 +拖 +洞 +授 +镜 +辛 +壮 +锋 +贫 +虚 +弯 +摩 +泰 +幼 +廷 +尊 +窗 +纲 +弄 +隶 +疑 +氏 +宫 +姐 +震 +瑞 +怪 +尤 +琴 +循 +描 +膜 +违 +夹 +腰 +缘 +珠 +穷 +森 +枝 +竹 +沟 +催 +绳 +忆 +邦 +剩 +幸 +浆 +栏 +拥 +牙 +贮 +礼 +滤 +钠 +纹 +罢 +拍 +咱 +喊 +袖 +埃 +勤 +罚 +焦 +潜 +伍 +墨 +欲 +缝 +姓 +刊 +饱 +仿 +奖 +铝 +鬼 +丽 +跨 +默 +挖 +链 +扫 +喝 +袋 +炭 +污 +幕 +诸 +弧 +励 +梅 +奶 +洁 +灾 +舟 +鉴 +苯 +讼 +抱 +毁 +懂 +寒 +智 +埔 +寄 +届 +跃 +渡 +挑 +丹 +艰 +贝 +碰 +拔 +爹 +戴 +码 +梦 +芽 +熔 +赤 +渔 +哭 +敬 +颗 +奔 +铅 +仲 +虎 +稀 +妹 +乏 +珍 +申 +桌 +遵 +允 +隆 +螺 +仓 +魏 +锐 +晓 +氮 +兼 +隐 +碍 +赫 +拨 +忠 +肃 +缸 +牵 +抢 +博 +巧 +壳 +兄 +杜 +讯 +诚 +碧 +祥 +柯 +页 +巡 +矩 +悲 +灌 +龄 +伦 +票 +寻 +桂 +铺 +圣 +恐 +恰 +郑 +趣 +抬 +荒 +腾 +贴 +柔 +滴 +猛 +阔 +辆 +妻 +填 +撤 +储 +签 +闹 +扰 +紫 +砂 +递 +戏 +吊 +陶 +伐 +喂 +疗 +瓶 +婆 +抚 +臂 +摸 +忍 +虾 +蜡 +邻 +胸 +巩 +挤 +偶 +弃 +槽 +劲 +乳 +邓 +吉 +仁 +烂 +砖 +租 +乌 +舰 +伴 +瓜 +浅 +丙 +暂 +燥 +橡 +柳 +迷 +暖 +牌 +秧 +胆 +详 +簧 +踏 +瓷 +谱 +呆 +宾 +糊 +洛 +辉 +愤 +竞 +隙 +怒 +粘 +乃 +绪 +肩 +籍 +敏 +涂 +熙 +皆 +侦 +悬 +掘 +享 +纠 +醒 +狂 +锁 +淀 +恨 +牲 +霸 +爬 +赏 +逆 +玩 +陵 +祝 +秒 +浙 +貌 +役 +彼 +悉 +鸭 +趋 +凤 +晨 +畜 +辈 +秩 +卵 +署 +梯 +炎 +滩 +棋 +驱 +筛 +峡 +冒 +啥 +寿 +译 +浸 +泉 +帽 +迟 +硅 +疆 +贷 +漏 +稿 +冠 +嫩 +胁 +芯 +牢 +叛 +蚀 +奥 +鸣 +岭 +羊 +凭 +串 +塘 +绘 +酵 +融 +盆 +锡 +庙 +筹 +冻 +辅 +摄 +袭 +筋 +拒 +僚 +旱 +钾 +鸟 +漆 +沈 +眉 +疏 +添 +棒 +穗 +硝 +韩 +逼 +扭 +侨 +凉 +挺 +碗 +栽 +炒 +杯 +患 +馏 +劝 +豪 +辽 +勃 +鸿 +旦 +吏 +拜 +狗 +埋 +辊 +掩 +饮 +搬 +骂 +辞 +勾 +扣 +估 +蒋 +绒 +雾 +丈 +朵 +姆 +拟 +宇 +辑 +陕 +雕 +偿 +蓄 +崇 +剪 +倡 +厅 +咬 +驶 +薯 +刷 +斥 +番 +赋 +奉 +佛 +浇 +漫 +曼 +扇 +钙 +桃 +扶 +仔 +返 +俗 +亏 +腔 +鞋 +棱 +覆 +框 +悄 +叔 +撞 +骗 +勘 +旺 +沸 +孤 +吐 +孟 +渠 +屈 +疾 +妙 +惜 +仰 +狠 +胀 +谐 +抛 +霉 +桑 +岗 +嘛 +衰 +盗 +渗 +脏 +赖 +涌 +甜 +曹 +阅 +肌 +哩 +厉 +烃 +纬 +毅 +昨 +伪 +症 +煮 +叹 +钉 +搭 +茎 +笼 +酷 +偷 +弓 +锥 +恒 +杰 +坑 +鼻 +翼 +纶 +叙 +狱 +逮 +罐 +络 +棚 +抑 +膨 +蔬 +寺 +骤 +穆 +冶 +枯 +册 +尸 +凸 +绅 +坯 +牺 +焰 +轰 +欣 +晋 +瘦 +御 +锭 +锦 +丧 +旬 +锻 +垄 +搜 +扑 +邀 +亭 +酯 +迈 +舒 +脆 +酶 +闲 +忧 +酚 +顽 +羽 +涨 +卸 +仗 +陪 +辟 +惩 +杭 +姚 +肚 +捉 +飘 +漂 +昆 +欺 +吾 +郎 +烷 +汁 +呵 +饰 +萧 +雅 +邮 +迁 +燕 +撒 +姻 +赴 +宴 +烦 +债 +帐 +斑 +铃 +旨 +醇 +董 +饼 +雏 +姿 +拌 +傅 +腹 +妥 +揉 +贤 +拆 +歪 +葡 +胺 +丢 +浩 +徽 +昂 +垫 +挡 +览 +贪 +慰 +缴 +汪 +慌 +冯 +诺 +姜 +谊 +凶 +劣 +诬 +耀 +昏 +躺 +盈 +骑 +乔 +溪 +丛 +卢 +抹 +闷 +咨 +刮 +驾 +缆 +悟 +摘 +铒 +掷 +颇 +幻 +柄 +惠 +惨 +佳 +仇 +腊 +窝 +涤 +剑 +瞧 +堡 +泼 +葱 +罩 +霍 +捞 +胎 +苍 +滨 +俩 +捅 +湘 +砍 +霞 +邵 +萄 +疯 +淮 +遂 +熊 +粪 +烘 +宿 +档 +戈 +驳 +嫂 +裕 +徙 +箭 +捐 +肠 +撑 +晒 +辨 +殿 +莲 +摊 +搅 +酱 +屏 +疫 +哀 +蔡 +堵 +沫 +皱 +畅 +叠 +阁 +莱 +敲 +辖 +钩 +痕 +坝 +巷 +饿 +祸 +丘 +玄 +溜 +曰 +逻 +彭 +尝 +卿 +妨 +艇 +吞 +韦 +怨 +矮 +歇 diff --git a/src/main/resources/chinese_traditional.txt b/src/main/resources/chinese_traditional.txt new file mode 100644 index 000000000..9b0204792 --- /dev/null +++ b/src/main/resources/chinese_traditional.txt @@ -0,0 +1,2048 @@ +的 +一 +是 +在 +不 +了 +有 +和 +人 +這 +中 +大 +為 +上 +個 +國 +我 +以 +要 +他 +時 +來 +用 +們 +生 +到 +作 +地 +於 +出 +就 +分 +對 +成 +會 +可 +主 +發 +年 +動 +同 +工 +也 +能 +下 +過 +子 +說 +產 +種 +面 +而 +方 +後 +多 +定 +行 +學 +法 +所 +民 +得 +經 +十 +三 +之 +進 +著 +等 +部 +度 +家 +電 +力 +裡 +如 +水 +化 +高 +自 +二 +理 +起 +小 +物 +現 +實 +加 +量 +都 +兩 +體 +制 +機 +當 +使 +點 +從 +業 +本 +去 +把 +性 +好 +應 +開 +它 +合 +還 +因 +由 +其 +些 +然 +前 +外 +天 +政 +四 +日 +那 +社 +義 +事 +平 +形 +相 +全 +表 +間 +樣 +與 +關 +各 +重 +新 +線 +內 +數 +正 +心 +反 +你 +明 +看 +原 +又 +麼 +利 +比 +或 +但 +質 +氣 +第 +向 +道 +命 +此 +變 +條 +只 +沒 +結 +解 +問 +意 +建 +月 +公 +無 +系 +軍 +很 +情 +者 +最 +立 +代 +想 +已 +通 +並 +提 +直 +題 +黨 +程 +展 +五 +果 +料 +象 +員 +革 +位 +入 +常 +文 +總 +次 +品 +式 +活 +設 +及 +管 +特 +件 +長 +求 +老 +頭 +基 +資 +邊 +流 +路 +級 +少 +圖 +山 +統 +接 +知 +較 +將 +組 +見 +計 +別 +她 +手 +角 +期 +根 +論 +運 +農 +指 +幾 +九 +區 +強 +放 +決 +西 +被 +幹 +做 +必 +戰 +先 +回 +則 +任 +取 +據 +處 +隊 +南 +給 +色 +光 +門 +即 +保 +治 +北 +造 +百 +規 +熱 +領 +七 +海 +口 +東 +導 +器 +壓 +志 +世 +金 +增 +爭 +濟 +階 +油 +思 +術 +極 +交 +受 +聯 +什 +認 +六 +共 +權 +收 +證 +改 +清 +美 +再 +採 +轉 +更 +單 +風 +切 +打 +白 +教 +速 +花 +帶 +安 +場 +身 +車 +例 +真 +務 +具 +萬 +每 +目 +至 +達 +走 +積 +示 +議 +聲 +報 +鬥 +完 +類 +八 +離 +華 +名 +確 +才 +科 +張 +信 +馬 +節 +話 +米 +整 +空 +元 +況 +今 +集 +溫 +傳 +土 +許 +步 +群 +廣 +石 +記 +需 +段 +研 +界 +拉 +林 +律 +叫 +且 +究 +觀 +越 +織 +裝 +影 +算 +低 +持 +音 +眾 +書 +布 +复 +容 +兒 +須 +際 +商 +非 +驗 +連 +斷 +深 +難 +近 +礦 +千 +週 +委 +素 +技 +備 +半 +辦 +青 +省 +列 +習 +響 +約 +支 +般 +史 +感 +勞 +便 +團 +往 +酸 +歷 +市 +克 +何 +除 +消 +構 +府 +稱 +太 +準 +精 +值 +號 +率 +族 +維 +劃 +選 +標 +寫 +存 +候 +毛 +親 +快 +效 +斯 +院 +查 +江 +型 +眼 +王 +按 +格 +養 +易 +置 +派 +層 +片 +始 +卻 +專 +狀 +育 +廠 +京 +識 +適 +屬 +圓 +包 +火 +住 +調 +滿 +縣 +局 +照 +參 +紅 +細 +引 +聽 +該 +鐵 +價 +嚴 +首 +底 +液 +官 +德 +隨 +病 +蘇 +失 +爾 +死 +講 +配 +女 +黃 +推 +顯 +談 +罪 +神 +藝 +呢 +席 +含 +企 +望 +密 +批 +營 +項 +防 +舉 +球 +英 +氧 +勢 +告 +李 +台 +落 +木 +幫 +輪 +破 +亞 +師 +圍 +注 +遠 +字 +材 +排 +供 +河 +態 +封 +另 +施 +減 +樹 +溶 +怎 +止 +案 +言 +士 +均 +武 +固 +葉 +魚 +波 +視 +僅 +費 +緊 +愛 +左 +章 +早 +朝 +害 +續 +輕 +服 +試 +食 +充 +兵 +源 +判 +護 +司 +足 +某 +練 +差 +致 +板 +田 +降 +黑 +犯 +負 +擊 +范 +繼 +興 +似 +餘 +堅 +曲 +輸 +修 +故 +城 +夫 +夠 +送 +筆 +船 +佔 +右 +財 +吃 +富 +春 +職 +覺 +漢 +畫 +功 +巴 +跟 +雖 +雜 +飛 +檢 +吸 +助 +昇 +陽 +互 +初 +創 +抗 +考 +投 +壞 +策 +古 +徑 +換 +未 +跑 +留 +鋼 +曾 +端 +責 +站 +簡 +述 +錢 +副 +盡 +帝 +射 +草 +衝 +承 +獨 +令 +限 +阿 +宣 +環 +雙 +請 +超 +微 +讓 +控 +州 +良 +軸 +找 +否 +紀 +益 +依 +優 +頂 +礎 +載 +倒 +房 +突 +坐 +粉 +敵 +略 +客 +袁 +冷 +勝 +絕 +析 +塊 +劑 +測 +絲 +協 +訴 +念 +陳 +仍 +羅 +鹽 +友 +洋 +錯 +苦 +夜 +刑 +移 +頻 +逐 +靠 +混 +母 +短 +皮 +終 +聚 +汽 +村 +雲 +哪 +既 +距 +衛 +停 +烈 +央 +察 +燒 +迅 +境 +若 +印 +洲 +刻 +括 +激 +孔 +搞 +甚 +室 +待 +核 +校 +散 +侵 +吧 +甲 +遊 +久 +菜 +味 +舊 +模 +湖 +貨 +損 +預 +阻 +毫 +普 +穩 +乙 +媽 +植 +息 +擴 +銀 +語 +揮 +酒 +守 +拿 +序 +紙 +醫 +缺 +雨 +嗎 +針 +劉 +啊 +急 +唱 +誤 +訓 +願 +審 +附 +獲 +茶 +鮮 +糧 +斤 +孩 +脫 +硫 +肥 +善 +龍 +演 +父 +漸 +血 +歡 +械 +掌 +歌 +沙 +剛 +攻 +謂 +盾 +討 +晚 +粒 +亂 +燃 +矛 +乎 +殺 +藥 +寧 +魯 +貴 +鐘 +煤 +讀 +班 +伯 +香 +介 +迫 +句 +豐 +培 +握 +蘭 +擔 +弦 +蛋 +沉 +假 +穿 +執 +答 +樂 +誰 +順 +煙 +縮 +徵 +臉 +喜 +松 +腳 +困 +異 +免 +背 +星 +福 +買 +染 +井 +概 +慢 +怕 +磁 +倍 +祖 +皇 +促 +靜 +補 +評 +翻 +肉 +踐 +尼 +衣 +寬 +揚 +棉 +希 +傷 +操 +垂 +秋 +宜 +氫 +套 +督 +振 +架 +亮 +末 +憲 +慶 +編 +牛 +觸 +映 +雷 +銷 +詩 +座 +居 +抓 +裂 +胞 +呼 +娘 +景 +威 +綠 +晶 +厚 +盟 +衡 +雞 +孫 +延 +危 +膠 +屋 +鄉 +臨 +陸 +顧 +掉 +呀 +燈 +歲 +措 +束 +耐 +劇 +玉 +趙 +跳 +哥 +季 +課 +凱 +胡 +額 +款 +紹 +卷 +齊 +偉 +蒸 +殖 +永 +宗 +苗 +川 +爐 +岩 +弱 +零 +楊 +奏 +沿 +露 +桿 +探 +滑 +鎮 +飯 +濃 +航 +懷 +趕 +庫 +奪 +伊 +靈 +稅 +途 +滅 +賽 +歸 +召 +鼓 +播 +盤 +裁 +險 +康 +唯 +錄 +菌 +純 +借 +糖 +蓋 +橫 +符 +私 +努 +堂 +域 +槍 +潤 +幅 +哈 +竟 +熟 +蟲 +澤 +腦 +壤 +碳 +歐 +遍 +側 +寨 +敢 +徹 +慮 +斜 +薄 +庭 +納 +彈 +飼 +伸 +折 +麥 +濕 +暗 +荷 +瓦 +塞 +床 +築 +惡 +戶 +訪 +塔 +奇 +透 +梁 +刀 +旋 +跡 +卡 +氯 +遇 +份 +毒 +泥 +退 +洗 +擺 +灰 +彩 +賣 +耗 +夏 +擇 +忙 +銅 +獻 +硬 +予 +繁 +圈 +雪 +函 +亦 +抽 +篇 +陣 +陰 +丁 +尺 +追 +堆 +雄 +迎 +泛 +爸 +樓 +避 +謀 +噸 +野 +豬 +旗 +累 +偏 +典 +館 +索 +秦 +脂 +潮 +爺 +豆 +忽 +托 +驚 +塑 +遺 +愈 +朱 +替 +纖 +粗 +傾 +尚 +痛 +楚 +謝 +奮 +購 +磨 +君 +池 +旁 +碎 +骨 +監 +捕 +弟 +暴 +割 +貫 +殊 +釋 +詞 +亡 +壁 +頓 +寶 +午 +塵 +聞 +揭 +炮 +殘 +冬 +橋 +婦 +警 +綜 +招 +吳 +付 +浮 +遭 +徐 +您 +搖 +谷 +贊 +箱 +隔 +訂 +男 +吹 +園 +紛 +唐 +敗 +宋 +玻 +巨 +耕 +坦 +榮 +閉 +灣 +鍵 +凡 +駐 +鍋 +救 +恩 +剝 +凝 +鹼 +齒 +截 +煉 +麻 +紡 +禁 +廢 +盛 +版 +緩 +淨 +睛 +昌 +婚 +涉 +筒 +嘴 +插 +岸 +朗 +莊 +街 +藏 +姑 +貿 +腐 +奴 +啦 +慣 +乘 +夥 +恢 +勻 +紗 +扎 +辯 +耳 +彪 +臣 +億 +璃 +抵 +脈 +秀 +薩 +俄 +網 +舞 +店 +噴 +縱 +寸 +汗 +掛 +洪 +賀 +閃 +柬 +爆 +烯 +津 +稻 +牆 +軟 +勇 +像 +滾 +厘 +蒙 +芳 +肯 +坡 +柱 +盪 +腿 +儀 +旅 +尾 +軋 +冰 +貢 +登 +黎 +削 +鑽 +勒 +逃 +障 +氨 +郭 +峰 +幣 +港 +伏 +軌 +畝 +畢 +擦 +莫 +刺 +浪 +秘 +援 +株 +健 +售 +股 +島 +甘 +泡 +睡 +童 +鑄 +湯 +閥 +休 +匯 +舍 +牧 +繞 +炸 +哲 +磷 +績 +朋 +淡 +尖 +啟 +陷 +柴 +呈 +徒 +顏 +淚 +稍 +忘 +泵 +藍 +拖 +洞 +授 +鏡 +辛 +壯 +鋒 +貧 +虛 +彎 +摩 +泰 +幼 +廷 +尊 +窗 +綱 +弄 +隸 +疑 +氏 +宮 +姐 +震 +瑞 +怪 +尤 +琴 +循 +描 +膜 +違 +夾 +腰 +緣 +珠 +窮 +森 +枝 +竹 +溝 +催 +繩 +憶 +邦 +剩 +幸 +漿 +欄 +擁 +牙 +貯 +禮 +濾 +鈉 +紋 +罷 +拍 +咱 +喊 +袖 +埃 +勤 +罰 +焦 +潛 +伍 +墨 +欲 +縫 +姓 +刊 +飽 +仿 +獎 +鋁 +鬼 +麗 +跨 +默 +挖 +鏈 +掃 +喝 +袋 +炭 +污 +幕 +諸 +弧 +勵 +梅 +奶 +潔 +災 +舟 +鑑 +苯 +訟 +抱 +毀 +懂 +寒 +智 +埔 +寄 +屆 +躍 +渡 +挑 +丹 +艱 +貝 +碰 +拔 +爹 +戴 +碼 +夢 +芽 +熔 +赤 +漁 +哭 +敬 +顆 +奔 +鉛 +仲 +虎 +稀 +妹 +乏 +珍 +申 +桌 +遵 +允 +隆 +螺 +倉 +魏 +銳 +曉 +氮 +兼 +隱 +礙 +赫 +撥 +忠 +肅 +缸 +牽 +搶 +博 +巧 +殼 +兄 +杜 +訊 +誠 +碧 +祥 +柯 +頁 +巡 +矩 +悲 +灌 +齡 +倫 +票 +尋 +桂 +鋪 +聖 +恐 +恰 +鄭 +趣 +抬 +荒 +騰 +貼 +柔 +滴 +猛 +闊 +輛 +妻 +填 +撤 +儲 +簽 +鬧 +擾 +紫 +砂 +遞 +戲 +吊 +陶 +伐 +餵 +療 +瓶 +婆 +撫 +臂 +摸 +忍 +蝦 +蠟 +鄰 +胸 +鞏 +擠 +偶 +棄 +槽 +勁 +乳 +鄧 +吉 +仁 +爛 +磚 +租 +烏 +艦 +伴 +瓜 +淺 +丙 +暫 +燥 +橡 +柳 +迷 +暖 +牌 +秧 +膽 +詳 +簧 +踏 +瓷 +譜 +呆 +賓 +糊 +洛 +輝 +憤 +競 +隙 +怒 +粘 +乃 +緒 +肩 +籍 +敏 +塗 +熙 +皆 +偵 +懸 +掘 +享 +糾 +醒 +狂 +鎖 +淀 +恨 +牲 +霸 +爬 +賞 +逆 +玩 +陵 +祝 +秒 +浙 +貌 +役 +彼 +悉 +鴨 +趨 +鳳 +晨 +畜 +輩 +秩 +卵 +署 +梯 +炎 +灘 +棋 +驅 +篩 +峽 +冒 +啥 +壽 +譯 +浸 +泉 +帽 +遲 +矽 +疆 +貸 +漏 +稿 +冠 +嫩 +脅 +芯 +牢 +叛 +蝕 +奧 +鳴 +嶺 +羊 +憑 +串 +塘 +繪 +酵 +融 +盆 +錫 +廟 +籌 +凍 +輔 +攝 +襲 +筋 +拒 +僚 +旱 +鉀 +鳥 +漆 +沈 +眉 +疏 +添 +棒 +穗 +硝 +韓 +逼 +扭 +僑 +涼 +挺 +碗 +栽 +炒 +杯 +患 +餾 +勸 +豪 +遼 +勃 +鴻 +旦 +吏 +拜 +狗 +埋 +輥 +掩 +飲 +搬 +罵 +辭 +勾 +扣 +估 +蔣 +絨 +霧 +丈 +朵 +姆 +擬 +宇 +輯 +陝 +雕 +償 +蓄 +崇 +剪 +倡 +廳 +咬 +駛 +薯 +刷 +斥 +番 +賦 +奉 +佛 +澆 +漫 +曼 +扇 +鈣 +桃 +扶 +仔 +返 +俗 +虧 +腔 +鞋 +棱 +覆 +框 +悄 +叔 +撞 +騙 +勘 +旺 +沸 +孤 +吐 +孟 +渠 +屈 +疾 +妙 +惜 +仰 +狠 +脹 +諧 +拋 +黴 +桑 +崗 +嘛 +衰 +盜 +滲 +臟 +賴 +湧 +甜 +曹 +閱 +肌 +哩 +厲 +烴 +緯 +毅 +昨 +偽 +症 +煮 +嘆 +釘 +搭 +莖 +籠 +酷 +偷 +弓 +錐 +恆 +傑 +坑 +鼻 +翼 +綸 +敘 +獄 +逮 +罐 +絡 +棚 +抑 +膨 +蔬 +寺 +驟 +穆 +冶 +枯 +冊 +屍 +凸 +紳 +坯 +犧 +焰 +轟 +欣 +晉 +瘦 +禦 +錠 +錦 +喪 +旬 +鍛 +壟 +搜 +撲 +邀 +亭 +酯 +邁 +舒 +脆 +酶 +閒 +憂 +酚 +頑 +羽 +漲 +卸 +仗 +陪 +闢 +懲 +杭 +姚 +肚 +捉 +飄 +漂 +昆 +欺 +吾 +郎 +烷 +汁 +呵 +飾 +蕭 +雅 +郵 +遷 +燕 +撒 +姻 +赴 +宴 +煩 +債 +帳 +斑 +鈴 +旨 +醇 +董 +餅 +雛 +姿 +拌 +傅 +腹 +妥 +揉 +賢 +拆 +歪 +葡 +胺 +丟 +浩 +徽 +昂 +墊 +擋 +覽 +貪 +慰 +繳 +汪 +慌 +馮 +諾 +姜 +誼 +兇 +劣 +誣 +耀 +昏 +躺 +盈 +騎 +喬 +溪 +叢 +盧 +抹 +悶 +諮 +刮 +駕 +纜 +悟 +摘 +鉺 +擲 +頗 +幻 +柄 +惠 +慘 +佳 +仇 +臘 +窩 +滌 +劍 +瞧 +堡 +潑 +蔥 +罩 +霍 +撈 +胎 +蒼 +濱 +倆 +捅 +湘 +砍 +霞 +邵 +萄 +瘋 +淮 +遂 +熊 +糞 +烘 +宿 +檔 +戈 +駁 +嫂 +裕 +徙 +箭 +捐 +腸 +撐 +曬 +辨 +殿 +蓮 +攤 +攪 +醬 +屏 +疫 +哀 +蔡 +堵 +沫 +皺 +暢 +疊 +閣 +萊 +敲 +轄 +鉤 +痕 +壩 +巷 +餓 +禍 +丘 +玄 +溜 +曰 +邏 +彭 +嘗 +卿 +妨 +艇 +吞 +韋 +怨 +矮 +歇 diff --git a/src/main/resources/english.txt b/src/main/resources/english.txt new file mode 100644 index 000000000..f78ccaf2c --- /dev/null +++ b/src/main/resources/english.txt @@ -0,0 +1,2048 @@ +abandon +ability +able +about +above +absent +absorb +abstract +absurd +abuse +access +accident +account +accuse +achieve +acid +acoustic +acquire +across +act +action +actor +actress +actual +adapt +add +addict +address +adjust +admit +adult +advance +advice +aerobic +affair +afford +afraid +again +age +agent +agree +ahead +aim +air +airport +aisle +alarm +album +alcohol +alert +alien +all +alley +allow +almost +alone +alpha +already +also +alter +always +amateur +amazing +among +amount +amused +analyst +anchor +ancient +anger +angle +angry +animal +ankle +announce +annual +another +answer +antenna +antique +anxiety +any +apart +apology +appear +apple +approve +april +arch +arctic +area +arena +argue +arm +armed +armor +army +around +arrange +arrest +arrive +arrow +art +artefact +artist +artwork +ask +aspect +assault +asset +assist +assume +asthma +athlete +atom +attack +attend +attitude +attract +auction +audit +august +aunt +author +auto +autumn +average +avocado +avoid +awake +aware +away +awesome +awful +awkward +axis +baby +bachelor +bacon +badge +bag +balance +balcony +ball +bamboo +banana +banner +bar +barely +bargain +barrel +base +basic +basket +battle +beach +bean +beauty +because +become +beef +before +begin +behave +behind +believe +below +belt +bench +benefit +best +betray +better +between +beyond +bicycle +bid +bike +bind +biology +bird +birth +bitter +black +blade +blame +blanket +blast +bleak +bless +blind +blood +blossom +blouse +blue +blur +blush +board +boat +body +boil +bomb +bone +bonus +book +boost +border +boring +borrow +boss +bottom +bounce +box +boy +bracket +brain +brand +brass +brave +bread +breeze +brick +bridge +brief +bright +bring +brisk +broccoli +broken +bronze +broom +brother +brown +brush +bubble +buddy +budget +buffalo +build +bulb +bulk +bullet +bundle +bunker +burden +burger +burst +bus +business +busy +butter +buyer +buzz +cabbage +cabin +cable +cactus +cage +cake +call +calm +camera +camp +can +canal +cancel +candy +cannon +canoe +canvas +canyon +capable +capital +captain +car +carbon +card +cargo +carpet +carry +cart +case +cash +casino +castle +casual +cat +catalog +catch +category +cattle +caught +cause +caution +cave +ceiling +celery +cement +census +century +cereal +certain +chair +chalk +champion +change +chaos +chapter +charge +chase +chat +cheap +check +cheese +chef +cherry +chest +chicken +chief +child +chimney +choice +choose +chronic +chuckle +chunk +churn +cigar +cinnamon +circle +citizen +city +civil +claim +clap +clarify +claw +clay +clean +clerk +clever +click +client +cliff +climb +clinic +clip +clock +clog +close +cloth +cloud +clown +club +clump +cluster +clutch +coach +coast +coconut +code +coffee +coil +coin +collect +color +column +combine +come +comfort +comic +common +company +concert +conduct +confirm +congress +connect +consider +control +convince +cook +cool +copper +copy +coral +core +corn +correct +cost +cotton +couch +country +couple +course +cousin +cover +coyote +crack +cradle +craft +cram +crane +crash +crater +crawl +crazy +cream +credit +creek +crew +cricket +crime +crisp +critic +crop +cross +crouch +crowd +crucial +cruel +cruise +crumble +crunch +crush +cry +crystal +cube +culture +cup +cupboard +curious +current +curtain +curve +cushion +custom +cute +cycle +dad +damage +damp +dance +danger +daring +dash +daughter +dawn +day +deal +debate +debris +decade +december +decide +decline +decorate +decrease +deer +defense +define +defy +degree +delay +deliver +demand +demise +denial +dentist +deny +depart +depend +deposit +depth +deputy +derive +describe +desert +design +desk +despair +destroy +detail +detect +develop +device +devote +diagram +dial +diamond +diary +dice +diesel +diet +differ +digital +dignity +dilemma +dinner +dinosaur +direct +dirt +disagree +discover +disease +dish +dismiss +disorder +display +distance +divert +divide +divorce +dizzy +doctor +document +dog +doll +dolphin +domain +donate +donkey +donor +door +dose +double +dove +draft +dragon +drama +drastic +draw +dream +dress +drift +drill +drink +drip +drive +drop +drum +dry +duck +dumb +dune +during +dust +dutch +duty +dwarf +dynamic +eager +eagle +early +earn +earth +easily +east +easy +echo +ecology +economy +edge +edit +educate +effort +egg +eight +either +elbow +elder +electric +elegant +element +elephant +elevator +elite +else +embark +embody +embrace +emerge +emotion +employ +empower +empty +enable +enact +end +endless +endorse +enemy +energy +enforce +engage +engine +enhance +enjoy +enlist +enough +enrich +enroll +ensure +enter +entire +entry +envelope +episode +equal +equip +era +erase +erode +erosion +error +erupt +escape +essay +essence +estate +eternal +ethics +evidence +evil +evoke +evolve +exact +example +excess +exchange +excite +exclude +excuse +execute +exercise +exhaust +exhibit +exile +exist +exit +exotic +expand +expect +expire +explain +expose +express +extend +extra +eye +eyebrow +fabric +face +faculty +fade +faint +faith +fall +false +fame +family +famous +fan +fancy +fantasy +farm +fashion +fat +fatal +father +fatigue +fault +favorite +feature +february +federal +fee +feed +feel +female +fence +festival +fetch +fever +few +fiber +fiction +field +figure +file +film +filter +final +find +fine +finger +finish +fire +firm +first +fiscal +fish +fit +fitness +fix +flag +flame +flash +flat +flavor +flee +flight +flip +float +flock +floor +flower +fluid +flush +fly +foam +focus +fog +foil +fold +follow +food +foot +force +forest +forget +fork +fortune +forum +forward +fossil +foster +found +fox +fragile +frame +frequent +fresh +friend +fringe +frog +front +frost +frown +frozen +fruit +fuel +fun +funny +furnace +fury +future +gadget +gain +galaxy +gallery +game +gap +garage +garbage +garden +garlic +garment +gas +gasp +gate +gather +gauge +gaze +general +genius +genre +gentle +genuine +gesture +ghost +giant +gift +giggle +ginger +giraffe +girl +give +glad +glance +glare +glass +glide +glimpse +globe +gloom +glory +glove +glow +glue +goat +goddess +gold +good +goose +gorilla +gospel +gossip +govern +gown +grab +grace +grain +grant +grape +grass +gravity +great +green +grid +grief +grit +grocery +group +grow +grunt +guard +guess +guide +guilt +guitar +gun +gym +habit +hair +half +hammer +hamster +hand +happy +harbor +hard +harsh +harvest +hat +have +hawk +hazard +head +health +heart +heavy +hedgehog +height +hello +helmet +help +hen +hero +hidden +high +hill +hint +hip +hire +history +hobby +hockey +hold +hole +holiday +hollow +home +honey +hood +hope +horn +horror +horse +hospital +host +hotel +hour +hover +hub +huge +human +humble +humor +hundred +hungry +hunt +hurdle +hurry +hurt +husband +hybrid +ice +icon +idea +identify +idle +ignore +ill +illegal +illness +image +imitate +immense +immune +impact +impose +improve +impulse +inch +include +income +increase +index +indicate +indoor +industry +infant +inflict +inform +inhale +inherit +initial +inject +injury +inmate +inner +innocent +input +inquiry +insane +insect +inside +inspire +install +intact +interest +into +invest +invite +involve +iron +island +isolate +issue +item +ivory +jacket +jaguar +jar +jazz +jealous +jeans +jelly +jewel +job +join +joke +journey +joy +judge +juice +jump +jungle +junior +junk +just +kangaroo +keen +keep +ketchup +key +kick +kid +kidney +kind +kingdom +kiss +kit +kitchen +kite +kitten +kiwi +knee +knife +knock +know +lab +label +labor +ladder +lady +lake +lamp +language +laptop +large +later +latin +laugh +laundry +lava +law +lawn +lawsuit +layer +lazy +leader +leaf +learn +leave +lecture +left +leg +legal +legend +leisure +lemon +lend +length +lens +leopard +lesson +letter +level +liar +liberty +library +license +life +lift +light +like +limb +limit +link +lion +liquid +list +little +live +lizard +load +loan +lobster +local +lock +logic +lonely +long +loop +lottery +loud +lounge +love +loyal +lucky +luggage +lumber +lunar +lunch +luxury +lyrics +machine +mad +magic +magnet +maid +mail +main +major +make +mammal +man +manage +mandate +mango +mansion +manual +maple +marble +march +margin +marine +market +marriage +mask +mass +master +match +material +math +matrix +matter +maximum +maze +meadow +mean +measure +meat +mechanic +medal +media +melody +melt +member +memory +mention +menu +mercy +merge +merit +merry +mesh +message +metal +method +middle +midnight +milk +million +mimic +mind +minimum +minor +minute +miracle +mirror +misery +miss +mistake +mix +mixed +mixture +mobile +model +modify +mom +moment +monitor +monkey +monster +month +moon +moral +more +morning +mosquito +mother +motion +motor +mountain +mouse +move +movie +much +muffin +mule +multiply +muscle +museum +mushroom +music +must +mutual +myself +mystery +myth +naive +name +napkin +narrow +nasty +nation +nature +near +neck +need +negative +neglect +neither +nephew +nerve +nest +net +network +neutral +never +news +next +nice +night +noble +noise +nominee +noodle +normal +north +nose +notable +note +nothing +notice +novel +now +nuclear +number +nurse +nut +oak +obey +object +oblige +obscure +observe +obtain +obvious +occur +ocean +october +odor +off +offer +office +often +oil +okay +old +olive +olympic +omit +once +one +onion +online +only +open +opera +opinion +oppose +option +orange +orbit +orchard +order +ordinary +organ +orient +original +orphan +ostrich +other +outdoor +outer +output +outside +oval +oven +over +own +owner +oxygen +oyster +ozone +pact +paddle +page +pair +palace +palm +panda +panel +panic +panther +paper +parade +parent +park +parrot +party +pass +patch +path +patient +patrol +pattern +pause +pave +payment +peace +peanut +pear +peasant +pelican +pen +penalty +pencil +people +pepper +perfect +permit +person +pet +phone +photo +phrase +physical +piano +picnic +picture +piece +pig +pigeon +pill +pilot +pink +pioneer +pipe +pistol +pitch +pizza +place +planet +plastic +plate +play +please +pledge +pluck +plug +plunge +poem +poet +point +polar +pole +police +pond +pony +pool +popular +portion +position +possible +post +potato +pottery +poverty +powder +power +practice +praise +predict +prefer +prepare +present +pretty +prevent +price +pride +primary +print +priority +prison +private +prize +problem +process +produce +profit +program +project +promote +proof +property +prosper +protect +proud +provide +public +pudding +pull +pulp +pulse +pumpkin +punch +pupil +puppy +purchase +purity +purpose +purse +push +put +puzzle +pyramid +quality +quantum +quarter +question +quick +quit +quiz +quote +rabbit +raccoon +race +rack +radar +radio +rail +rain +raise +rally +ramp +ranch +random +range +rapid +rare +rate +rather +raven +raw +razor +ready +real +reason +rebel +rebuild +recall +receive +recipe +record +recycle +reduce +reflect +reform +refuse +region +regret +regular +reject +relax +release +relief +rely +remain +remember +remind +remove +render +renew +rent +reopen +repair +repeat +replace +report +require +rescue +resemble +resist +resource +response +result +retire +retreat +return +reunion +reveal +review +reward +rhythm +rib +ribbon +rice +rich +ride +ridge +rifle +right +rigid +ring +riot +ripple +risk +ritual +rival +river +road +roast +robot +robust +rocket +romance +roof +rookie +room +rose +rotate +rough +round +route +royal +rubber +rude +rug +rule +run +runway +rural +sad +saddle +sadness +safe +sail +salad +salmon +salon +salt +salute +same +sample +sand +satisfy +satoshi +sauce +sausage +save +say +scale +scan +scare +scatter +scene +scheme +school +science +scissors +scorpion +scout +scrap +screen +script +scrub +sea +search +season +seat +second +secret +section +security +seed +seek +segment +select +sell +seminar +senior +sense +sentence +series +service +session +settle +setup +seven +shadow +shaft +shallow +share +shed +shell +sheriff +shield +shift +shine +ship +shiver +shock +shoe +shoot +shop +short +shoulder +shove +shrimp +shrug +shuffle +shy +sibling +sick +side +siege +sight +sign +silent +silk +silly +silver +similar +simple +since +sing +siren +sister +situate +six +size +skate +sketch +ski +skill +skin +skirt +skull +slab +slam +sleep +slender +slice +slide +slight +slim +slogan +slot +slow +slush +small +smart +smile +smoke +smooth +snack +snake +snap +sniff +snow +soap +soccer +social +sock +soda +soft +solar +soldier +solid +solution +solve +someone +song +soon +sorry +sort +soul +sound +soup +source +south +space +spare +spatial +spawn +speak +special +speed +spell +spend +sphere +spice +spider +spike +spin +spirit +split +spoil +sponsor +spoon +sport +spot +spray +spread +spring +spy +square +squeeze +squirrel +stable +stadium +staff +stage +stairs +stamp +stand +start +state +stay +steak +steel +stem +step +stereo +stick +still +sting +stock +stomach +stone +stool +story +stove +strategy +street +strike +strong +struggle +student +stuff +stumble +style +subject +submit +subway +success +such +sudden +suffer +sugar +suggest +suit +summer +sun +sunny +sunset +super +supply +supreme +sure +surface +surge +surprise +surround +survey +suspect +sustain +swallow +swamp +swap +swarm +swear +sweet +swift +swim +swing +switch +sword +symbol +symptom +syrup +system +table +tackle +tag +tail +talent +talk +tank +tape +target +task +taste +tattoo +taxi +teach +team +tell +ten +tenant +tennis +tent +term +test +text +thank +that +theme +then +theory +there +they +thing +this +thought +three +thrive +throw +thumb +thunder +ticket +tide +tiger +tilt +timber +time +tiny +tip +tired +tissue +title +toast +tobacco +today +toddler +toe +together +toilet +token +tomato +tomorrow +tone +tongue +tonight +tool +tooth +top +topic +topple +torch +tornado +tortoise +toss +total +tourist +toward +tower +town +toy +track +trade +traffic +tragic +train +transfer +trap +trash +travel +tray +treat +tree +trend +trial +tribe +trick +trigger +trim +trip +trophy +trouble +truck +true +truly +trumpet +trust +truth +try +tube +tuition +tumble +tuna +tunnel +turkey +turn +turtle +twelve +twenty +twice +twin +twist +two +type +typical +ugly +umbrella +unable +unaware +uncle +uncover +under +undo +unfair +unfold +unhappy +uniform +unique +unit +universe +unknown +unlock +until +unusual +unveil +update +upgrade +uphold +upon +upper +upset +urban +urge +usage +use +used +useful +useless +usual +utility +vacant +vacuum +vague +valid +valley +valve +van +vanish +vapor +various +vast +vault +vehicle +velvet +vendor +venture +venue +verb +verify +version +very +vessel +veteran +viable +vibrant +vicious +victory +video +view +village +vintage +violin +virtual +virus +visa +visit +visual +vital +vivid +vocal +voice +void +volcano +volume +vote +voyage +wage +wagon +wait +walk +wall +walnut +want +warfare +warm +warrior +wash +wasp +waste +water +wave +way +wealth +weapon +wear +weasel +weather +web +wedding +weekend +weird +welcome +west +wet +whale +what +wheat +wheel +when +where +whip +whisper +wide +width +wife +wild +will +win +window +wine +wing +wink +winner +winter +wire +wisdom +wise +wish +witness +wolf +woman +wonder +wood +wool +word +work +world +worry +worth +wrap +wreck +wrestle +wrist +write +wrong +yard +year +yellow +you +young +youth +zebra +zero +zone +zoo \ No newline at end of file diff --git a/src/main/resources/french.txt b/src/main/resources/french.txt new file mode 100644 index 000000000..1d749904f --- /dev/null +++ b/src/main/resources/french.txt @@ -0,0 +1,2048 @@ +abaisser +abandon +abdiquer +abeille +abolir +aborder +aboutir +aboyer +abrasif +abreuver +abriter +abroger +abrupt +absence +absolu +absurde +abusif +abyssal +académie +acajou +acarien +accabler +accepter +acclamer +accolade +accroche +accuser +acerbe +achat +acheter +aciduler +acier +acompte +acquérir +acronyme +acteur +actif +actuel +adepte +adéquat +adhésif +adjectif +adjuger +admettre +admirer +adopter +adorer +adoucir +adresse +adroit +adulte +adverbe +aérer +aéronef +affaire +affecter +affiche +affreux +affubler +agacer +agencer +agile +agiter +agrafer +agréable +agrume +aider +aiguille +ailier +aimable +aisance +ajouter +ajuster +alarmer +alchimie +alerte +algèbre +algue +aliéner +aliment +alléger +alliage +allouer +allumer +alourdir +alpaga +altesse +alvéole +amateur +ambigu +ambre +aménager +amertume +amidon +amiral +amorcer +amour +amovible +amphibie +ampleur +amusant +analyse +anaphore +anarchie +anatomie +ancien +anéantir +angle +angoisse +anguleux +animal +annexer +annonce +annuel +anodin +anomalie +anonyme +anormal +antenne +antidote +anxieux +apaiser +apéritif +aplanir +apologie +appareil +appeler +apporter +appuyer +aquarium +aqueduc +arbitre +arbuste +ardeur +ardoise +argent +arlequin +armature +armement +armoire +armure +arpenter +arracher +arriver +arroser +arsenic +artériel +article +aspect +asphalte +aspirer +assaut +asservir +assiette +associer +assurer +asticot +astre +astuce +atelier +atome +atrium +atroce +attaque +attentif +attirer +attraper +aubaine +auberge +audace +audible +augurer +aurore +automne +autruche +avaler +avancer +avarice +avenir +averse +aveugle +aviateur +avide +avion +aviser +avoine +avouer +avril +axial +axiome +badge +bafouer +bagage +baguette +baignade +balancer +balcon +baleine +balisage +bambin +bancaire +bandage +banlieue +bannière +banquier +barbier +baril +baron +barque +barrage +bassin +bastion +bataille +bateau +batterie +baudrier +bavarder +belette +bélier +belote +bénéfice +berceau +berger +berline +bermuda +besace +besogne +bétail +beurre +biberon +bicycle +bidule +bijou +bilan +bilingue +billard +binaire +biologie +biopsie +biotype +biscuit +bison +bistouri +bitume +bizarre +blafard +blague +blanchir +blessant +blinder +blond +bloquer +blouson +bobard +bobine +boire +boiser +bolide +bonbon +bondir +bonheur +bonifier +bonus +bordure +borne +botte +boucle +boueux +bougie +boulon +bouquin +bourse +boussole +boutique +boxeur +branche +brasier +brave +brebis +brèche +breuvage +bricoler +brigade +brillant +brioche +brique +brochure +broder +bronzer +brousse +broyeur +brume +brusque +brutal +bruyant +buffle +buisson +bulletin +bureau +burin +bustier +butiner +butoir +buvable +buvette +cabanon +cabine +cachette +cadeau +cadre +caféine +caillou +caisson +calculer +calepin +calibre +calmer +calomnie +calvaire +camarade +caméra +camion +campagne +canal +caneton +canon +cantine +canular +capable +caporal +caprice +capsule +capter +capuche +carabine +carbone +caresser +caribou +carnage +carotte +carreau +carton +cascade +casier +casque +cassure +causer +caution +cavalier +caverne +caviar +cédille +ceinture +céleste +cellule +cendrier +censurer +central +cercle +cérébral +cerise +cerner +cerveau +cesser +chagrin +chaise +chaleur +chambre +chance +chapitre +charbon +chasseur +chaton +chausson +chavirer +chemise +chenille +chéquier +chercher +cheval +chien +chiffre +chignon +chimère +chiot +chlorure +chocolat +choisir +chose +chouette +chrome +chute +cigare +cigogne +cimenter +cinéma +cintrer +circuler +cirer +cirque +citerne +citoyen +citron +civil +clairon +clameur +claquer +classe +clavier +client +cligner +climat +clivage +cloche +clonage +cloporte +cobalt +cobra +cocasse +cocotier +coder +codifier +coffre +cogner +cohésion +coiffer +coincer +colère +colibri +colline +colmater +colonel +combat +comédie +commande +compact +concert +conduire +confier +congeler +connoter +consonne +contact +convexe +copain +copie +corail +corbeau +cordage +corniche +corpus +correct +cortège +cosmique +costume +coton +coude +coupure +courage +couteau +couvrir +coyote +crabe +crainte +cravate +crayon +créature +créditer +crémeux +creuser +crevette +cribler +crier +cristal +critère +croire +croquer +crotale +crucial +cruel +crypter +cubique +cueillir +cuillère +cuisine +cuivre +culminer +cultiver +cumuler +cupide +curatif +curseur +cyanure +cycle +cylindre +cynique +daigner +damier +danger +danseur +dauphin +débattre +débiter +déborder +débrider +débutant +décaler +décembre +déchirer +décider +déclarer +décorer +décrire +décupler +dédale +déductif +déesse +défensif +défiler +défrayer +dégager +dégivrer +déglutir +dégrafer +déjeuner +délice +déloger +demander +demeurer +démolir +dénicher +dénouer +dentelle +dénuder +départ +dépenser +déphaser +déplacer +déposer +déranger +dérober +désastre +descente +désert +désigner +désobéir +dessiner +destrier +détacher +détester +détourer +détresse +devancer +devenir +deviner +devoir +diable +dialogue +diamant +dicter +différer +digérer +digital +digne +diluer +dimanche +diminuer +dioxyde +directif +diriger +discuter +disposer +dissiper +distance +divertir +diviser +docile +docteur +dogme +doigt +domaine +domicile +dompter +donateur +donjon +donner +dopamine +dortoir +dorure +dosage +doseur +dossier +dotation +douanier +double +douceur +douter +doyen +dragon +draper +dresser +dribbler +droiture +duperie +duplexe +durable +durcir +dynastie +éblouir +écarter +écharpe +échelle +éclairer +éclipse +éclore +écluse +école +économie +écorce +écouter +écraser +écrémer +écrivain +écrou +écume +écureuil +édifier +éduquer +effacer +effectif +effigie +effort +effrayer +effusion +égaliser +égarer +éjecter +élaborer +élargir +électron +élégant +éléphant +élève +éligible +élitisme +éloge +élucider +éluder +emballer +embellir +embryon +émeraude +émission +emmener +émotion +émouvoir +empereur +employer +emporter +emprise +émulsion +encadrer +enchère +enclave +encoche +endiguer +endosser +endroit +enduire +énergie +enfance +enfermer +enfouir +engager +engin +englober +énigme +enjamber +enjeu +enlever +ennemi +ennuyeux +enrichir +enrobage +enseigne +entasser +entendre +entier +entourer +entraver +énumérer +envahir +enviable +envoyer +enzyme +éolien +épaissir +épargne +épatant +épaule +épicerie +épidémie +épier +épilogue +épine +épisode +épitaphe +époque +épreuve +éprouver +épuisant +équerre +équipe +ériger +érosion +erreur +éruption +escalier +espadon +espèce +espiègle +espoir +esprit +esquiver +essayer +essence +essieu +essorer +estime +estomac +estrade +étagère +étaler +étanche +étatique +éteindre +étendoir +éternel +éthanol +éthique +ethnie +étirer +étoffer +étoile +étonnant +étourdir +étrange +étroit +étude +euphorie +évaluer +évasion +éventail +évidence +éviter +évolutif +évoquer +exact +exagérer +exaucer +exceller +excitant +exclusif +excuse +exécuter +exemple +exercer +exhaler +exhorter +exigence +exiler +exister +exotique +expédier +explorer +exposer +exprimer +exquis +extensif +extraire +exulter +fable +fabuleux +facette +facile +facture +faiblir +falaise +fameux +famille +farceur +farfelu +farine +farouche +fasciner +fatal +fatigue +faucon +fautif +faveur +favori +fébrile +féconder +fédérer +félin +femme +fémur +fendoir +féodal +fermer +féroce +ferveur +festival +feuille +feutre +février +fiasco +ficeler +fictif +fidèle +figure +filature +filetage +filière +filleul +filmer +filou +filtrer +financer +finir +fiole +firme +fissure +fixer +flairer +flamme +flasque +flatteur +fléau +flèche +fleur +flexion +flocon +flore +fluctuer +fluide +fluvial +folie +fonderie +fongible +fontaine +forcer +forgeron +formuler +fortune +fossile +foudre +fougère +fouiller +foulure +fourmi +fragile +fraise +franchir +frapper +frayeur +frégate +freiner +frelon +frémir +frénésie +frère +friable +friction +frisson +frivole +froid +fromage +frontal +frotter +fruit +fugitif +fuite +fureur +furieux +furtif +fusion +futur +gagner +galaxie +galerie +gambader +garantir +gardien +garnir +garrigue +gazelle +gazon +géant +gélatine +gélule +gendarme +général +génie +genou +gentil +géologie +géomètre +géranium +germe +gestuel +geyser +gibier +gicler +girafe +givre +glace +glaive +glisser +globe +gloire +glorieux +golfeur +gomme +gonfler +gorge +gorille +goudron +gouffre +goulot +goupille +gourmand +goutte +graduel +graffiti +graine +grand +grappin +gratuit +gravir +grenat +griffure +griller +grimper +grogner +gronder +grotte +groupe +gruger +grutier +gruyère +guépard +guerrier +guide +guimauve +guitare +gustatif +gymnaste +gyrostat +habitude +hachoir +halte +hameau +hangar +hanneton +haricot +harmonie +harpon +hasard +hélium +hématome +herbe +hérisson +hermine +héron +hésiter +heureux +hiberner +hibou +hilarant +histoire +hiver +homard +hommage +homogène +honneur +honorer +honteux +horde +horizon +horloge +hormone +horrible +houleux +housse +hublot +huileux +humain +humble +humide +humour +hurler +hydromel +hygiène +hymne +hypnose +idylle +ignorer +iguane +illicite +illusion +image +imbiber +imiter +immense +immobile +immuable +impact +impérial +implorer +imposer +imprimer +imputer +incarner +incendie +incident +incliner +incolore +indexer +indice +inductif +inédit +ineptie +inexact +infini +infliger +informer +infusion +ingérer +inhaler +inhiber +injecter +injure +innocent +inoculer +inonder +inscrire +insecte +insigne +insolite +inspirer +instinct +insulter +intact +intense +intime +intrigue +intuitif +inutile +invasion +inventer +inviter +invoquer +ironique +irradier +irréel +irriter +isoler +ivoire +ivresse +jaguar +jaillir +jambe +janvier +jardin +jauger +jaune +javelot +jetable +jeton +jeudi +jeunesse +joindre +joncher +jongler +joueur +jouissif +journal +jovial +joyau +joyeux +jubiler +jugement +junior +jupon +juriste +justice +juteux +juvénile +kayak +kimono +kiosque +label +labial +labourer +lacérer +lactose +lagune +laine +laisser +laitier +lambeau +lamelle +lampe +lanceur +langage +lanterne +lapin +largeur +larme +laurier +lavabo +lavoir +lecture +légal +léger +légume +lessive +lettre +levier +lexique +lézard +liasse +libérer +libre +licence +licorne +liège +lièvre +ligature +ligoter +ligue +limer +limite +limonade +limpide +linéaire +lingot +lionceau +liquide +lisière +lister +lithium +litige +littoral +livreur +logique +lointain +loisir +lombric +loterie +louer +lourd +loutre +louve +loyal +lubie +lucide +lucratif +lueur +lugubre +luisant +lumière +lunaire +lundi +luron +lutter +luxueux +machine +magasin +magenta +magique +maigre +maillon +maintien +mairie +maison +majorer +malaxer +maléfice +malheur +malice +mallette +mammouth +mandater +maniable +manquant +manteau +manuel +marathon +marbre +marchand +mardi +maritime +marqueur +marron +marteler +mascotte +massif +matériel +matière +matraque +maudire +maussade +mauve +maximal +méchant +méconnu +médaille +médecin +méditer +méduse +meilleur +mélange +mélodie +membre +mémoire +menacer +mener +menhir +mensonge +mentor +mercredi +mérite +merle +messager +mesure +métal +météore +méthode +métier +meuble +miauler +microbe +miette +mignon +migrer +milieu +million +mimique +mince +minéral +minimal +minorer +minute +miracle +miroiter +missile +mixte +mobile +moderne +moelleux +mondial +moniteur +monnaie +monotone +monstre +montagne +monument +moqueur +morceau +morsure +mortier +moteur +motif +mouche +moufle +moulin +mousson +mouton +mouvant +multiple +munition +muraille +murène +murmure +muscle +muséum +musicien +mutation +muter +mutuel +myriade +myrtille +mystère +mythique +nageur +nappe +narquois +narrer +natation +nation +nature +naufrage +nautique +navire +nébuleux +nectar +néfaste +négation +négliger +négocier +neige +nerveux +nettoyer +neurone +neutron +neveu +niche +nickel +nitrate +niveau +noble +nocif +nocturne +noirceur +noisette +nomade +nombreux +nommer +normatif +notable +notifier +notoire +nourrir +nouveau +novateur +novembre +novice +nuage +nuancer +nuire +nuisible +numéro +nuptial +nuque +nutritif +obéir +objectif +obliger +obscur +observer +obstacle +obtenir +obturer +occasion +occuper +océan +octobre +octroyer +octupler +oculaire +odeur +odorant +offenser +officier +offrir +ogive +oiseau +oisillon +olfactif +olivier +ombrage +omettre +onctueux +onduler +onéreux +onirique +opale +opaque +opérer +opinion +opportun +opprimer +opter +optique +orageux +orange +orbite +ordonner +oreille +organe +orgueil +orifice +ornement +orque +ortie +osciller +osmose +ossature +otarie +ouragan +ourson +outil +outrager +ouvrage +ovation +oxyde +oxygène +ozone +paisible +palace +palmarès +palourde +palper +panache +panda +pangolin +paniquer +panneau +panorama +pantalon +papaye +papier +papoter +papyrus +paradoxe +parcelle +paresse +parfumer +parler +parole +parrain +parsemer +partager +parure +parvenir +passion +pastèque +paternel +patience +patron +pavillon +pavoiser +payer +paysage +peigne +peintre +pelage +pélican +pelle +pelouse +peluche +pendule +pénétrer +pénible +pensif +pénurie +pépite +péplum +perdrix +perforer +période +permuter +perplexe +persil +perte +peser +pétale +petit +pétrir +peuple +pharaon +phobie +phoque +photon +phrase +physique +piano +pictural +pièce +pierre +pieuvre +pilote +pinceau +pipette +piquer +pirogue +piscine +piston +pivoter +pixel +pizza +placard +plafond +plaisir +planer +plaque +plastron +plateau +pleurer +plexus +pliage +plomb +plonger +pluie +plumage +pochette +poésie +poète +pointe +poirier +poisson +poivre +polaire +policier +pollen +polygone +pommade +pompier +ponctuel +pondérer +poney +portique +position +posséder +posture +potager +poteau +potion +pouce +poulain +poumon +pourpre +poussin +pouvoir +prairie +pratique +précieux +prédire +préfixe +prélude +prénom +présence +prétexte +prévoir +primitif +prince +prison +priver +problème +procéder +prodige +profond +progrès +proie +projeter +prologue +promener +propre +prospère +protéger +prouesse +proverbe +prudence +pruneau +psychose +public +puceron +puiser +pulpe +pulsar +punaise +punitif +pupitre +purifier +puzzle +pyramide +quasar +querelle +question +quiétude +quitter +quotient +racine +raconter +radieux +ragondin +raideur +raisin +ralentir +rallonge +ramasser +rapide +rasage +ratisser +ravager +ravin +rayonner +réactif +réagir +réaliser +réanimer +recevoir +réciter +réclamer +récolter +recruter +reculer +recycler +rédiger +redouter +refaire +réflexe +réformer +refrain +refuge +régalien +région +réglage +régulier +réitérer +rejeter +rejouer +relatif +relever +relief +remarque +remède +remise +remonter +remplir +remuer +renard +renfort +renifler +renoncer +rentrer +renvoi +replier +reporter +reprise +reptile +requin +réserve +résineux +résoudre +respect +rester +résultat +rétablir +retenir +réticule +retomber +retracer +réunion +réussir +revanche +revivre +révolte +révulsif +richesse +rideau +rieur +rigide +rigoler +rincer +riposter +risible +risque +rituel +rival +rivière +rocheux +romance +rompre +ronce +rondin +roseau +rosier +rotatif +rotor +rotule +rouge +rouille +rouleau +routine +royaume +ruban +rubis +ruche +ruelle +rugueux +ruiner +ruisseau +ruser +rustique +rythme +sabler +saboter +sabre +sacoche +safari +sagesse +saisir +salade +salive +salon +saluer +samedi +sanction +sanglier +sarcasme +sardine +saturer +saugrenu +saumon +sauter +sauvage +savant +savonner +scalpel +scandale +scélérat +scénario +sceptre +schéma +science +scinder +score +scrutin +sculpter +séance +sécable +sécher +secouer +sécréter +sédatif +séduire +seigneur +séjour +sélectif +semaine +sembler +semence +séminal +sénateur +sensible +sentence +séparer +séquence +serein +sergent +sérieux +serrure +sérum +service +sésame +sévir +sevrage +sextuple +sidéral +siècle +siéger +siffler +sigle +signal +silence +silicium +simple +sincère +sinistre +siphon +sirop +sismique +situer +skier +social +socle +sodium +soigneux +soldat +soleil +solitude +soluble +sombre +sommeil +somnoler +sonde +songeur +sonnette +sonore +sorcier +sortir +sosie +sottise +soucieux +soudure +souffle +soulever +soupape +source +soutirer +souvenir +spacieux +spatial +spécial +sphère +spiral +stable +station +sternum +stimulus +stipuler +strict +studieux +stupeur +styliste +sublime +substrat +subtil +subvenir +succès +sucre +suffixe +suggérer +suiveur +sulfate +superbe +supplier +surface +suricate +surmener +surprise +sursaut +survie +suspect +syllabe +symbole +symétrie +synapse +syntaxe +système +tabac +tablier +tactile +tailler +talent +talisman +talonner +tambour +tamiser +tangible +tapis +taquiner +tarder +tarif +tartine +tasse +tatami +tatouage +taupe +taureau +taxer +témoin +temporel +tenaille +tendre +teneur +tenir +tension +terminer +terne +terrible +tétine +texte +thème +théorie +thérapie +thorax +tibia +tiède +timide +tirelire +tiroir +tissu +titane +titre +tituber +toboggan +tolérant +tomate +tonique +tonneau +toponyme +torche +tordre +tornade +torpille +torrent +torse +tortue +totem +toucher +tournage +tousser +toxine +traction +trafic +tragique +trahir +train +trancher +travail +trèfle +tremper +trésor +treuil +triage +tribunal +tricoter +trilogie +triomphe +tripler +triturer +trivial +trombone +tronc +tropical +troupeau +tuile +tulipe +tumulte +tunnel +turbine +tuteur +tutoyer +tuyau +tympan +typhon +typique +tyran +ubuesque +ultime +ultrason +unanime +unifier +union +unique +unitaire +univers +uranium +urbain +urticant +usage +usine +usuel +usure +utile +utopie +vacarme +vaccin +vagabond +vague +vaillant +vaincre +vaisseau +valable +valise +vallon +valve +vampire +vanille +vapeur +varier +vaseux +vassal +vaste +vecteur +vedette +végétal +véhicule +veinard +véloce +vendredi +vénérer +venger +venimeux +ventouse +verdure +vérin +vernir +verrou +verser +vertu +veston +vétéran +vétuste +vexant +vexer +viaduc +viande +victoire +vidange +vidéo +vignette +vigueur +vilain +village +vinaigre +violon +vipère +virement +virtuose +virus +visage +viseur +vision +visqueux +visuel +vital +vitesse +viticole +vitrine +vivace +vivipare +vocation +voguer +voile +voisin +voiture +volaille +volcan +voltiger +volume +vorace +vortex +voter +vouloir +voyage +voyelle +wagon +xénon +yacht +zèbre +zénith +zeste +zoologie diff --git a/src/main/resources/portuguese.txt b/src/main/resources/portuguese.txt new file mode 100644 index 000000000..4a8910550 --- /dev/null +++ b/src/main/resources/portuguese.txt @@ -0,0 +1,2048 @@ +abacate +abaixo +abalar +abater +abduzir +abelha +aberto +abismo +abotoar +abranger +abreviar +abrigar +abrupto +absinto +absoluto +absurdo +abutre +acabado +acalmar +acampar +acanhar +acaso +aceitar +acelerar +acenar +acervo +acessar +acetona +achatar +acidez +acima +acionado +acirrar +aclamar +aclive +acolhida +acomodar +acoplar +acordar +acumular +acusador +adaptar +adega +adentro +adepto +adequar +aderente +adesivo +adeus +adiante +aditivo +adjetivo +adjunto +admirar +adorar +adquirir +adubo +adverso +advogado +aeronave +afastar +aferir +afetivo +afinador +afivelar +aflito +afluente +afrontar +agachar +agarrar +agasalho +agenciar +agilizar +agiota +agitado +agora +agradar +agreste +agrupar +aguardar +agulha +ajoelhar +ajudar +ajustar +alameda +alarme +alastrar +alavanca +albergue +albino +alcatra +aldeia +alecrim +alegria +alertar +alface +alfinete +algum +alheio +aliar +alicate +alienar +alinhar +aliviar +almofada +alocar +alpiste +alterar +altitude +alucinar +alugar +aluno +alusivo +alvo +amaciar +amador +amarelo +amassar +ambas +ambiente +ameixa +amenizar +amido +amistoso +amizade +amolador +amontoar +amoroso +amostra +amparar +ampliar +ampola +anagrama +analisar +anarquia +anatomia +andaime +anel +anexo +angular +animar +anjo +anomalia +anotado +ansioso +anterior +anuidade +anunciar +anzol +apagador +apalpar +apanhado +apego +apelido +apertada +apesar +apetite +apito +aplauso +aplicada +apoio +apontar +aposta +aprendiz +aprovar +aquecer +arame +aranha +arara +arcada +ardente +areia +arejar +arenito +aresta +argiloso +argola +arma +arquivo +arraial +arrebate +arriscar +arroba +arrumar +arsenal +arterial +artigo +arvoredo +asfaltar +asilado +aspirar +assador +assinar +assoalho +assunto +astral +atacado +atadura +atalho +atarefar +atear +atender +aterro +ateu +atingir +atirador +ativo +atoleiro +atracar +atrevido +atriz +atual +atum +auditor +aumentar +aura +aurora +autismo +autoria +autuar +avaliar +avante +avaria +avental +avesso +aviador +avisar +avulso +axila +azarar +azedo +azeite +azulejo +babar +babosa +bacalhau +bacharel +bacia +bagagem +baiano +bailar +baioneta +bairro +baixista +bajular +baleia +baliza +balsa +banal +bandeira +banho +banir +banquete +barato +barbado +baronesa +barraca +barulho +baseado +bastante +batata +batedor +batida +batom +batucar +baunilha +beber +beijo +beirada +beisebol +beldade +beleza +belga +beliscar +bendito +bengala +benzer +berimbau +berlinda +berro +besouro +bexiga +bezerro +bico +bicudo +bienal +bifocal +bifurcar +bigorna +bilhete +bimestre +bimotor +biologia +biombo +biosfera +bipolar +birrento +biscoito +bisneto +bispo +bissexto +bitola +bizarro +blindado +bloco +bloquear +boato +bobagem +bocado +bocejo +bochecha +boicotar +bolada +boletim +bolha +bolo +bombeiro +bonde +boneco +bonita +borbulha +borda +boreal +borracha +bovino +boxeador +branco +brasa +braveza +breu +briga +brilho +brincar +broa +brochura +bronzear +broto +bruxo +bucha +budismo +bufar +bule +buraco +busca +busto +buzina +cabana +cabelo +cabide +cabo +cabrito +cacau +cacetada +cachorro +cacique +cadastro +cadeado +cafezal +caiaque +caipira +caixote +cajado +caju +calafrio +calcular +caldeira +calibrar +calmante +calota +camada +cambista +camisa +camomila +campanha +camuflar +canavial +cancelar +caneta +canguru +canhoto +canivete +canoa +cansado +cantar +canudo +capacho +capela +capinar +capotar +capricho +captador +capuz +caracol +carbono +cardeal +careca +carimbar +carneiro +carpete +carreira +cartaz +carvalho +casaco +casca +casebre +castelo +casulo +catarata +cativar +caule +causador +cautelar +cavalo +caverna +cebola +cedilha +cegonha +celebrar +celular +cenoura +censo +centeio +cercar +cerrado +certeiro +cerveja +cetim +cevada +chacota +chaleira +chamado +chapada +charme +chatice +chave +chefe +chegada +cheiro +cheque +chicote +chifre +chinelo +chocalho +chover +chumbo +chutar +chuva +cicatriz +ciclone +cidade +cidreira +ciente +cigana +cimento +cinto +cinza +ciranda +circuito +cirurgia +citar +clareza +clero +clicar +clone +clube +coado +coagir +cobaia +cobertor +cobrar +cocada +coelho +coentro +coeso +cogumelo +coibir +coifa +coiote +colar +coleira +colher +colidir +colmeia +colono +coluna +comando +combinar +comentar +comitiva +comover +complexo +comum +concha +condor +conectar +confuso +congelar +conhecer +conjugar +consumir +contrato +convite +cooperar +copeiro +copiador +copo +coquetel +coragem +cordial +corneta +coronha +corporal +correio +cortejo +coruja +corvo +cosseno +costela +cotonete +couro +couve +covil +cozinha +cratera +cravo +creche +credor +creme +crer +crespo +criada +criminal +crioulo +crise +criticar +crosta +crua +cruzeiro +cubano +cueca +cuidado +cujo +culatra +culminar +culpar +cultura +cumprir +cunhado +cupido +curativo +curral +cursar +curto +cuspir +custear +cutelo +damasco +datar +debater +debitar +deboche +debulhar +decalque +decimal +declive +decote +decretar +dedal +dedicado +deduzir +defesa +defumar +degelo +degrau +degustar +deitado +deixar +delator +delegado +delinear +delonga +demanda +demitir +demolido +dentista +depenado +depilar +depois +depressa +depurar +deriva +derramar +desafio +desbotar +descanso +desenho +desfiado +desgaste +desigual +deslize +desmamar +desova +despesa +destaque +desviar +detalhar +detentor +detonar +detrito +deusa +dever +devido +devotado +dezena +diagrama +dialeto +didata +difuso +digitar +dilatado +diluente +diminuir +dinastia +dinheiro +diocese +direto +discreta +disfarce +disparo +disquete +dissipar +distante +ditador +diurno +diverso +divisor +divulgar +dizer +dobrador +dolorido +domador +dominado +donativo +donzela +dormente +dorsal +dosagem +dourado +doutor +drenagem +drible +drogaria +duelar +duende +dueto +duplo +duquesa +durante +duvidoso +eclodir +ecoar +ecologia +edificar +edital +educado +efeito +efetivar +ejetar +elaborar +eleger +eleitor +elenco +elevador +eliminar +elogiar +embargo +embolado +embrulho +embutido +emenda +emergir +emissor +empatia +empenho +empinado +empolgar +emprego +empurrar +emulador +encaixe +encenado +enchente +encontro +endeusar +endossar +enfaixar +enfeite +enfim +engajado +engenho +englobar +engomado +engraxar +enguia +enjoar +enlatar +enquanto +enraizar +enrolado +enrugar +ensaio +enseada +ensino +ensopado +entanto +enteado +entidade +entortar +entrada +entulho +envergar +enviado +envolver +enxame +enxerto +enxofre +enxuto +epiderme +equipar +ereto +erguido +errata +erva +ervilha +esbanjar +esbelto +escama +escola +escrita +escuta +esfinge +esfolar +esfregar +esfumado +esgrima +esmalte +espanto +espelho +espiga +esponja +espreita +espumar +esquerda +estaca +esteira +esticar +estofado +estrela +estudo +esvaziar +etanol +etiqueta +euforia +europeu +evacuar +evaporar +evasivo +eventual +evidente +evoluir +exagero +exalar +examinar +exato +exausto +excesso +excitar +exclamar +executar +exemplo +exibir +exigente +exonerar +expandir +expelir +expirar +explanar +exposto +expresso +expulsar +externo +extinto +extrato +fabricar +fabuloso +faceta +facial +fada +fadiga +faixa +falar +falta +familiar +fandango +fanfarra +fantoche +fardado +farelo +farinha +farofa +farpa +fartura +fatia +fator +favorita +faxina +fazenda +fechado +feijoada +feirante +felino +feminino +fenda +feno +fera +feriado +ferrugem +ferver +festejar +fetal +feudal +fiapo +fibrose +ficar +ficheiro +figurado +fileira +filho +filme +filtrar +firmeza +fisgada +fissura +fita +fivela +fixador +fixo +flacidez +flamingo +flanela +flechada +flora +flutuar +fluxo +focal +focinho +fofocar +fogo +foguete +foice +folgado +folheto +forjar +formiga +forno +forte +fosco +fossa +fragata +fralda +frango +frasco +fraterno +freira +frente +fretar +frieza +friso +fritura +fronha +frustrar +fruteira +fugir +fulano +fuligem +fundar +fungo +funil +furador +furioso +futebol +gabarito +gabinete +gado +gaiato +gaiola +gaivota +galega +galho +galinha +galocha +ganhar +garagem +garfo +gargalo +garimpo +garoupa +garrafa +gasoduto +gasto +gata +gatilho +gaveta +gazela +gelado +geleia +gelo +gemada +gemer +gemido +generoso +gengiva +genial +genoma +genro +geologia +gerador +germinar +gesso +gestor +ginasta +gincana +gingado +girafa +girino +glacial +glicose +global +glorioso +goela +goiaba +golfe +golpear +gordura +gorjeta +gorro +gostoso +goteira +governar +gracejo +gradual +grafite +gralha +grampo +granada +gratuito +graveto +graxa +grego +grelhar +greve +grilo +grisalho +gritaria +grosso +grotesco +grudado +grunhido +gruta +guache +guarani +guaxinim +guerrear +guiar +guincho +guisado +gula +guloso +guru +habitar +harmonia +haste +haver +hectare +herdar +heresia +hesitar +hiato +hibernar +hidratar +hiena +hino +hipismo +hipnose +hipoteca +hoje +holofote +homem +honesto +honrado +hormonal +hospedar +humorado +iate +ideia +idoso +ignorado +igreja +iguana +ileso +ilha +iludido +iluminar +ilustrar +imagem +imediato +imenso +imersivo +iminente +imitador +imortal +impacto +impedir +implante +impor +imprensa +impune +imunizar +inalador +inapto +inativo +incenso +inchar +incidir +incluir +incolor +indeciso +indireto +indutor +ineficaz +inerente +infantil +infestar +infinito +inflamar +informal +infrator +ingerir +inibido +inicial +inimigo +injetar +inocente +inodoro +inovador +inox +inquieto +inscrito +inseto +insistir +inspetor +instalar +insulto +intacto +integral +intimar +intocado +intriga +invasor +inverno +invicto +invocar +iogurte +iraniano +ironizar +irreal +irritado +isca +isento +isolado +isqueiro +italiano +janeiro +jangada +janta +jararaca +jardim +jarro +jasmim +jato +javali +jazida +jejum +joaninha +joelhada +jogador +joia +jornal +jorrar +jovem +juba +judeu +judoca +juiz +julgador +julho +jurado +jurista +juro +justa +labareda +laboral +lacre +lactante +ladrilho +lagarta +lagoa +laje +lamber +lamentar +laminar +lampejo +lanche +lapidar +lapso +laranja +lareira +largura +lasanha +lastro +lateral +latido +lavanda +lavoura +lavrador +laxante +lazer +lealdade +lebre +legado +legendar +legista +leigo +leiloar +leitura +lembrete +leme +lenhador +lentilha +leoa +lesma +leste +letivo +letreiro +levar +leveza +levitar +liberal +libido +liderar +ligar +ligeiro +limitar +limoeiro +limpador +linda +linear +linhagem +liquidez +listagem +lisura +litoral +livro +lixa +lixeira +locador +locutor +lojista +lombo +lona +longe +lontra +lorde +lotado +loteria +loucura +lousa +louvar +luar +lucidez +lucro +luneta +lustre +lutador +luva +macaco +macete +machado +macio +madeira +madrinha +magnata +magreza +maior +mais +malandro +malha +malote +maluco +mamilo +mamoeiro +mamute +manada +mancha +mandato +manequim +manhoso +manivela +manobrar +mansa +manter +manusear +mapeado +maquinar +marcador +maresia +marfim +margem +marinho +marmita +maroto +marquise +marreco +martelo +marujo +mascote +masmorra +massagem +mastigar +matagal +materno +matinal +matutar +maxilar +medalha +medida +medusa +megafone +meiga +melancia +melhor +membro +memorial +menino +menos +mensagem +mental +merecer +mergulho +mesada +mesclar +mesmo +mesquita +mestre +metade +meteoro +metragem +mexer +mexicano +micro +migalha +migrar +milagre +milenar +milhar +mimado +minerar +minhoca +ministro +minoria +miolo +mirante +mirtilo +misturar +mocidade +moderno +modular +moeda +moer +moinho +moita +moldura +moleza +molho +molinete +molusco +montanha +moqueca +morango +morcego +mordomo +morena +mosaico +mosquete +mostarda +motel +motim +moto +motriz +muda +muito +mulata +mulher +multar +mundial +munido +muralha +murcho +muscular +museu +musical +nacional +nadador +naja +namoro +narina +narrado +nascer +nativa +natureza +navalha +navegar +navio +neblina +nebuloso +negativa +negociar +negrito +nervoso +neta +neural +nevasca +nevoeiro +ninar +ninho +nitidez +nivelar +nobreza +noite +noiva +nomear +nominal +nordeste +nortear +notar +noticiar +noturno +novelo +novilho +novo +nublado +nudez +numeral +nupcial +nutrir +nuvem +obcecado +obedecer +objetivo +obrigado +obscuro +obstetra +obter +obturar +ocidente +ocioso +ocorrer +oculista +ocupado +ofegante +ofensiva +oferenda +oficina +ofuscado +ogiva +olaria +oleoso +olhar +oliveira +ombro +omelete +omisso +omitir +ondulado +oneroso +ontem +opcional +operador +oponente +oportuno +oposto +orar +orbitar +ordem +ordinal +orfanato +orgasmo +orgulho +oriental +origem +oriundo +orla +ortodoxo +orvalho +oscilar +ossada +osso +ostentar +otimismo +ousadia +outono +outubro +ouvido +ovelha +ovular +oxidar +oxigenar +pacato +paciente +pacote +pactuar +padaria +padrinho +pagar +pagode +painel +pairar +paisagem +palavra +palestra +palheta +palito +palmada +palpitar +pancada +panela +panfleto +panqueca +pantanal +papagaio +papelada +papiro +parafina +parcial +pardal +parede +partida +pasmo +passado +pastel +patamar +patente +patinar +patrono +paulada +pausar +peculiar +pedalar +pedestre +pediatra +pedra +pegada +peitoral +peixe +pele +pelicano +penca +pendurar +peneira +penhasco +pensador +pente +perceber +perfeito +pergunta +perito +permitir +perna +perplexo +persiana +pertence +peruca +pescado +pesquisa +pessoa +petiscar +piada +picado +piedade +pigmento +pilastra +pilhado +pilotar +pimenta +pincel +pinguim +pinha +pinote +pintar +pioneiro +pipoca +piquete +piranha +pires +pirueta +piscar +pistola +pitanga +pivete +planta +plaqueta +platina +plebeu +plumagem +pluvial +pneu +poda +poeira +poetisa +polegada +policiar +poluente +polvilho +pomar +pomba +ponderar +pontaria +populoso +porta +possuir +postal +pote +poupar +pouso +povoar +praia +prancha +prato +praxe +prece +predador +prefeito +premiar +prensar +preparar +presilha +pretexto +prevenir +prezar +primata +princesa +prisma +privado +processo +produto +profeta +proibido +projeto +prometer +propagar +prosa +protetor +provador +publicar +pudim +pular +pulmonar +pulseira +punhal +punir +pupilo +pureza +puxador +quadra +quantia +quarto +quase +quebrar +queda +queijo +quente +querido +quimono +quina +quiosque +rabanada +rabisco +rachar +racionar +radial +raiar +rainha +raio +raiva +rajada +ralado +ramal +ranger +ranhura +rapadura +rapel +rapidez +raposa +raquete +raridade +rasante +rascunho +rasgar +raspador +rasteira +rasurar +ratazana +ratoeira +realeza +reanimar +reaver +rebaixar +rebelde +rebolar +recado +recente +recheio +recibo +recordar +recrutar +recuar +rede +redimir +redonda +reduzida +reenvio +refinar +refletir +refogar +refresco +refugiar +regalia +regime +regra +reinado +reitor +rejeitar +relativo +remador +remendo +remorso +renovado +reparo +repelir +repleto +repolho +represa +repudiar +requerer +resenha +resfriar +resgatar +residir +resolver +respeito +ressaca +restante +resumir +retalho +reter +retirar +retomada +retratar +revelar +revisor +revolta +riacho +rica +rigidez +rigoroso +rimar +ringue +risada +risco +risonho +robalo +rochedo +rodada +rodeio +rodovia +roedor +roleta +romano +roncar +rosado +roseira +rosto +rota +roteiro +rotina +rotular +rouco +roupa +roxo +rubro +rugido +rugoso +ruivo +rumo +rupestre +russo +sabor +saciar +sacola +sacudir +sadio +safira +saga +sagrada +saibro +salada +saleiro +salgado +saliva +salpicar +salsicha +saltar +salvador +sambar +samurai +sanar +sanfona +sangue +sanidade +sapato +sarda +sargento +sarjeta +saturar +saudade +saxofone +sazonal +secar +secular +seda +sedento +sediado +sedoso +sedutor +segmento +segredo +segundo +seiva +seleto +selvagem +semanal +semente +senador +senhor +sensual +sentado +separado +sereia +seringa +serra +servo +setembro +setor +sigilo +silhueta +silicone +simetria +simpatia +simular +sinal +sincero +singular +sinopse +sintonia +sirene +siri +situado +soberano +sobra +socorro +sogro +soja +solda +soletrar +solteiro +sombrio +sonata +sondar +sonegar +sonhador +sono +soprano +soquete +sorrir +sorteio +sossego +sotaque +soterrar +sovado +sozinho +suavizar +subida +submerso +subsolo +subtrair +sucata +sucesso +suco +sudeste +sufixo +sugador +sugerir +sujeito +sulfato +sumir +suor +superior +suplicar +suposto +suprimir +surdina +surfista +surpresa +surreal +surtir +suspiro +sustento +tabela +tablete +tabuada +tacho +tagarela +talher +talo +talvez +tamanho +tamborim +tampa +tangente +tanto +tapar +tapioca +tardio +tarefa +tarja +tarraxa +tatuagem +taurino +taxativo +taxista +teatral +tecer +tecido +teclado +tedioso +teia +teimar +telefone +telhado +tempero +tenente +tensor +tentar +termal +terno +terreno +tese +tesoura +testado +teto +textura +texugo +tiara +tigela +tijolo +timbrar +timidez +tingido +tinteiro +tiragem +titular +toalha +tocha +tolerar +tolice +tomada +tomilho +tonel +tontura +topete +tora +torcido +torneio +torque +torrada +torto +tostar +touca +toupeira +toxina +trabalho +tracejar +tradutor +trafegar +trajeto +trama +trancar +trapo +traseiro +tratador +travar +treino +tremer +trepidar +trevo +triagem +tribo +triciclo +tridente +trilogia +trindade +triplo +triturar +triunfal +trocar +trombeta +trova +trunfo +truque +tubular +tucano +tudo +tulipa +tupi +turbo +turma +turquesa +tutelar +tutorial +uivar +umbigo +unha +unidade +uniforme +urologia +urso +urtiga +urubu +usado +usina +usufruir +vacina +vadiar +vagaroso +vaidoso +vala +valente +validade +valores +vantagem +vaqueiro +varanda +vareta +varrer +vascular +vasilha +vassoura +vazar +vazio +veado +vedar +vegetar +veicular +veleiro +velhice +veludo +vencedor +vendaval +venerar +ventre +verbal +verdade +vereador +vergonha +vermelho +verniz +versar +vertente +vespa +vestido +vetorial +viaduto +viagem +viajar +viatura +vibrador +videira +vidraria +viela +viga +vigente +vigiar +vigorar +vilarejo +vinco +vinheta +vinil +violeta +virada +virtude +visitar +visto +vitral +viveiro +vizinho +voador +voar +vogal +volante +voleibol +voltagem +volumoso +vontade +vulto +vuvuzela +xadrez +xarope +xeque +xeretar +xerife +xingar +zangado +zarpar +zebu +zelador +zombar +zoologia +zumbido diff --git a/src/main/resources/spanish.txt b/src/main/resources/spanish.txt new file mode 100644 index 000000000..fdbc23c73 --- /dev/null +++ b/src/main/resources/spanish.txt @@ -0,0 +1,2048 @@ +ábaco +abdomen +abeja +abierto +abogado +abono +aborto +abrazo +abrir +abuelo +abuso +acabar +academia +acceso +acción +aceite +acelga +acento +aceptar +ácido +aclarar +acné +acoger +acoso +activo +acto +actriz +actuar +acudir +acuerdo +acusar +adicto +admitir +adoptar +adorno +aduana +adulto +aéreo +afectar +afición +afinar +afirmar +ágil +agitar +agonía +agosto +agotar +agregar +agrio +agua +agudo +águila +aguja +ahogo +ahorro +aire +aislar +ajedrez +ajeno +ajuste +alacrán +alambre +alarma +alba +álbum +alcalde +aldea +alegre +alejar +alerta +aleta +alfiler +alga +algodón +aliado +aliento +alivio +alma +almeja +almíbar +altar +alteza +altivo +alto +altura +alumno +alzar +amable +amante +amapola +amargo +amasar +ámbar +ámbito +ameno +amigo +amistad +amor +amparo +amplio +ancho +anciano +ancla +andar +andén +anemia +ángulo +anillo +ánimo +anís +anotar +antena +antiguo +antojo +anual +anular +anuncio +añadir +añejo +año +apagar +aparato +apetito +apio +aplicar +apodo +aporte +apoyo +aprender +aprobar +apuesta +apuro +arado +araña +arar +árbitro +árbol +arbusto +archivo +arco +arder +ardilla +arduo +área +árido +aries +armonía +arnés +aroma +arpa +arpón +arreglo +arroz +arruga +arte +artista +asa +asado +asalto +ascenso +asegurar +aseo +asesor +asiento +asilo +asistir +asno +asombro +áspero +astilla +astro +astuto +asumir +asunto +atajo +ataque +atar +atento +ateo +ático +atleta +átomo +atraer +atroz +atún +audaz +audio +auge +aula +aumento +ausente +autor +aval +avance +avaro +ave +avellana +avena +avestruz +avión +aviso +ayer +ayuda +ayuno +azafrán +azar +azote +azúcar +azufre +azul +baba +babor +bache +bahía +baile +bajar +balanza +balcón +balde +bambú +banco +banda +baño +barba +barco +barniz +barro +báscula +bastón +basura +batalla +batería +batir +batuta +baúl +bazar +bebé +bebida +bello +besar +beso +bestia +bicho +bien +bingo +blanco +bloque +blusa +boa +bobina +bobo +boca +bocina +boda +bodega +boina +bola +bolero +bolsa +bomba +bondad +bonito +bono +bonsái +borde +borrar +bosque +bote +botín +bóveda +bozal +bravo +brazo +brecha +breve +brillo +brinco +brisa +broca +broma +bronce +brote +bruja +brusco +bruto +buceo +bucle +bueno +buey +bufanda +bufón +búho +buitre +bulto +burbuja +burla +burro +buscar +butaca +buzón +caballo +cabeza +cabina +cabra +cacao +cadáver +cadena +caer +café +caída +caimán +caja +cajón +cal +calamar +calcio +caldo +calidad +calle +calma +calor +calvo +cama +cambio +camello +camino +campo +cáncer +candil +canela +canguro +canica +canto +caña +cañón +caoba +caos +capaz +capitán +capote +captar +capucha +cara +carbón +cárcel +careta +carga +cariño +carne +carpeta +carro +carta +casa +casco +casero +caspa +castor +catorce +catre +caudal +causa +cazo +cebolla +ceder +cedro +celda +célebre +celoso +célula +cemento +ceniza +centro +cerca +cerdo +cereza +cero +cerrar +certeza +césped +cetro +chacal +chaleco +champú +chancla +chapa +charla +chico +chiste +chivo +choque +choza +chuleta +chupar +ciclón +ciego +cielo +cien +cierto +cifra +cigarro +cima +cinco +cine +cinta +ciprés +circo +ciruela +cisne +cita +ciudad +clamor +clan +claro +clase +clave +cliente +clima +clínica +cobre +cocción +cochino +cocina +coco +código +codo +cofre +coger +cohete +cojín +cojo +cola +colcha +colegio +colgar +colina +collar +colmo +columna +combate +comer +comida +cómodo +compra +conde +conejo +conga +conocer +consejo +contar +copa +copia +corazón +corbata +corcho +cordón +corona +correr +coser +cosmos +costa +cráneo +cráter +crear +crecer +creído +crema +cría +crimen +cripta +crisis +cromo +crónica +croqueta +crudo +cruz +cuadro +cuarto +cuatro +cubo +cubrir +cuchara +cuello +cuento +cuerda +cuesta +cueva +cuidar +culebra +culpa +culto +cumbre +cumplir +cuna +cuneta +cuota +cupón +cúpula +curar +curioso +curso +curva +cutis +dama +danza +dar +dardo +dátil +deber +débil +década +decir +dedo +defensa +definir +dejar +delfín +delgado +delito +demora +denso +dental +deporte +derecho +derrota +desayuno +deseo +desfile +desnudo +destino +desvío +detalle +detener +deuda +día +diablo +diadema +diamante +diana +diario +dibujo +dictar +diente +dieta +diez +difícil +digno +dilema +diluir +dinero +directo +dirigir +disco +diseño +disfraz +diva +divino +doble +doce +dolor +domingo +don +donar +dorado +dormir +dorso +dos +dosis +dragón +droga +ducha +duda +duelo +dueño +dulce +dúo +duque +durar +dureza +duro +ébano +ebrio +echar +eco +ecuador +edad +edición +edificio +editor +educar +efecto +eficaz +eje +ejemplo +elefante +elegir +elemento +elevar +elipse +élite +elixir +elogio +eludir +embudo +emitir +emoción +empate +empeño +empleo +empresa +enano +encargo +enchufe +encía +enemigo +enero +enfado +enfermo +engaño +enigma +enlace +enorme +enredo +ensayo +enseñar +entero +entrar +envase +envío +época +equipo +erizo +escala +escena +escolar +escribir +escudo +esencia +esfera +esfuerzo +espada +espejo +espía +esposa +espuma +esquí +estar +este +estilo +estufa +etapa +eterno +ética +etnia +evadir +evaluar +evento +evitar +exacto +examen +exceso +excusa +exento +exigir +exilio +existir +éxito +experto +explicar +exponer +extremo +fábrica +fábula +fachada +fácil +factor +faena +faja +falda +fallo +falso +faltar +fama +familia +famoso +faraón +farmacia +farol +farsa +fase +fatiga +fauna +favor +fax +febrero +fecha +feliz +feo +feria +feroz +fértil +fervor +festín +fiable +fianza +fiar +fibra +ficción +ficha +fideo +fiebre +fiel +fiera +fiesta +figura +fijar +fijo +fila +filete +filial +filtro +fin +finca +fingir +finito +firma +flaco +flauta +flecha +flor +flota +fluir +flujo +flúor +fobia +foca +fogata +fogón +folio +folleto +fondo +forma +forro +fortuna +forzar +fosa +foto +fracaso +frágil +franja +frase +fraude +freír +freno +fresa +frío +frito +fruta +fuego +fuente +fuerza +fuga +fumar +función +funda +furgón +furia +fusil +fútbol +futuro +gacela +gafas +gaita +gajo +gala +galería +gallo +gamba +ganar +gancho +ganga +ganso +garaje +garza +gasolina +gastar +gato +gavilán +gemelo +gemir +gen +género +genio +gente +geranio +gerente +germen +gesto +gigante +gimnasio +girar +giro +glaciar +globo +gloria +gol +golfo +goloso +golpe +goma +gordo +gorila +gorra +gota +goteo +gozar +grada +gráfico +grano +grasa +gratis +grave +grieta +grillo +gripe +gris +grito +grosor +grúa +grueso +grumo +grupo +guante +guapo +guardia +guerra +guía +guiño +guion +guiso +guitarra +gusano +gustar +haber +hábil +hablar +hacer +hacha +hada +hallar +hamaca +harina +haz +hazaña +hebilla +hebra +hecho +helado +helio +hembra +herir +hermano +héroe +hervir +hielo +hierro +hígado +higiene +hijo +himno +historia +hocico +hogar +hoguera +hoja +hombre +hongo +honor +honra +hora +hormiga +horno +hostil +hoyo +hueco +huelga +huerta +hueso +huevo +huida +huir +humano +húmedo +humilde +humo +hundir +huracán +hurto +icono +ideal +idioma +ídolo +iglesia +iglú +igual +ilegal +ilusión +imagen +imán +imitar +impar +imperio +imponer +impulso +incapaz +índice +inerte +infiel +informe +ingenio +inicio +inmenso +inmune +innato +insecto +instante +interés +íntimo +intuir +inútil +invierno +ira +iris +ironía +isla +islote +jabalí +jabón +jamón +jarabe +jardín +jarra +jaula +jazmín +jefe +jeringa +jinete +jornada +joroba +joven +joya +juerga +jueves +juez +jugador +jugo +juguete +juicio +junco +jungla +junio +juntar +júpiter +jurar +justo +juvenil +juzgar +kilo +koala +labio +lacio +lacra +lado +ladrón +lagarto +lágrima +laguna +laico +lamer +lámina +lámpara +lana +lancha +langosta +lanza +lápiz +largo +larva +lástima +lata +látex +latir +laurel +lavar +lazo +leal +lección +leche +lector +leer +legión +legumbre +lejano +lengua +lento +leña +león +leopardo +lesión +letal +letra +leve +leyenda +libertad +libro +licor +líder +lidiar +lienzo +liga +ligero +lima +límite +limón +limpio +lince +lindo +línea +lingote +lino +linterna +líquido +liso +lista +litera +litio +litro +llaga +llama +llanto +llave +llegar +llenar +llevar +llorar +llover +lluvia +lobo +loción +loco +locura +lógica +logro +lombriz +lomo +lonja +lote +lucha +lucir +lugar +lujo +luna +lunes +lupa +lustro +luto +luz +maceta +macho +madera +madre +maduro +maestro +mafia +magia +mago +maíz +maldad +maleta +malla +malo +mamá +mambo +mamut +manco +mando +manejar +manga +maniquí +manjar +mano +manso +manta +mañana +mapa +máquina +mar +marco +marea +marfil +margen +marido +mármol +marrón +martes +marzo +masa +máscara +masivo +matar +materia +matiz +matriz +máximo +mayor +mazorca +mecha +medalla +medio +médula +mejilla +mejor +melena +melón +memoria +menor +mensaje +mente +menú +mercado +merengue +mérito +mes +mesón +meta +meter +método +metro +mezcla +miedo +miel +miembro +miga +mil +milagro +militar +millón +mimo +mina +minero +mínimo +minuto +miope +mirar +misa +miseria +misil +mismo +mitad +mito +mochila +moción +moda +modelo +moho +mojar +molde +moler +molino +momento +momia +monarca +moneda +monja +monto +moño +morada +morder +moreno +morir +morro +morsa +mortal +mosca +mostrar +motivo +mover +móvil +mozo +mucho +mudar +mueble +muela +muerte +muestra +mugre +mujer +mula +muleta +multa +mundo +muñeca +mural +muro +músculo +museo +musgo +música +muslo +nácar +nación +nadar +naipe +naranja +nariz +narrar +nasal +natal +nativo +natural +náusea +naval +nave +navidad +necio +néctar +negar +negocio +negro +neón +nervio +neto +neutro +nevar +nevera +nicho +nido +niebla +nieto +niñez +niño +nítido +nivel +nobleza +noche +nómina +noria +norma +norte +nota +noticia +novato +novela +novio +nube +nuca +núcleo +nudillo +nudo +nuera +nueve +nuez +nulo +número +nutria +oasis +obeso +obispo +objeto +obra +obrero +observar +obtener +obvio +oca +ocaso +océano +ochenta +ocho +ocio +ocre +octavo +octubre +oculto +ocupar +ocurrir +odiar +odio +odisea +oeste +ofensa +oferta +oficio +ofrecer +ogro +oído +oír +ojo +ola +oleada +olfato +olivo +olla +olmo +olor +olvido +ombligo +onda +onza +opaco +opción +ópera +opinar +oponer +optar +óptica +opuesto +oración +orador +oral +órbita +orca +orden +oreja +órgano +orgía +orgullo +oriente +origen +orilla +oro +orquesta +oruga +osadía +oscuro +osezno +oso +ostra +otoño +otro +oveja +óvulo +óxido +oxígeno +oyente +ozono +pacto +padre +paella +página +pago +país +pájaro +palabra +palco +paleta +pálido +palma +paloma +palpar +pan +panal +pánico +pantera +pañuelo +papá +papel +papilla +paquete +parar +parcela +pared +parir +paro +párpado +parque +párrafo +parte +pasar +paseo +pasión +paso +pasta +pata +patio +patria +pausa +pauta +pavo +payaso +peatón +pecado +pecera +pecho +pedal +pedir +pegar +peine +pelar +peldaño +pelea +peligro +pellejo +pelo +peluca +pena +pensar +peñón +peón +peor +pepino +pequeño +pera +percha +perder +pereza +perfil +perico +perla +permiso +perro +persona +pesa +pesca +pésimo +pestaña +pétalo +petróleo +pez +pezuña +picar +pichón +pie +piedra +pierna +pieza +pijama +pilar +piloto +pimienta +pino +pintor +pinza +piña +piojo +pipa +pirata +pisar +piscina +piso +pista +pitón +pizca +placa +plan +plata +playa +plaza +pleito +pleno +plomo +pluma +plural +pobre +poco +poder +podio +poema +poesía +poeta +polen +policía +pollo +polvo +pomada +pomelo +pomo +pompa +poner +porción +portal +posada +poseer +posible +poste +potencia +potro +pozo +prado +precoz +pregunta +premio +prensa +preso +previo +primo +príncipe +prisión +privar +proa +probar +proceso +producto +proeza +profesor +programa +prole +promesa +pronto +propio +próximo +prueba +público +puchero +pudor +pueblo +puerta +puesto +pulga +pulir +pulmón +pulpo +pulso +puma +punto +puñal +puño +pupa +pupila +puré +quedar +queja +quemar +querer +queso +quieto +química +quince +quitar +rábano +rabia +rabo +ración +radical +raíz +rama +rampa +rancho +rango +rapaz +rápido +rapto +rasgo +raspa +rato +rayo +raza +razón +reacción +realidad +rebaño +rebote +recaer +receta +rechazo +recoger +recreo +recto +recurso +red +redondo +reducir +reflejo +reforma +refrán +refugio +regalo +regir +regla +regreso +rehén +reino +reír +reja +relato +relevo +relieve +relleno +reloj +remar +remedio +remo +rencor +rendir +renta +reparto +repetir +reposo +reptil +res +rescate +resina +respeto +resto +resumen +retiro +retorno +retrato +reunir +revés +revista +rey +rezar +rico +riego +rienda +riesgo +rifa +rígido +rigor +rincón +riñón +río +riqueza +risa +ritmo +rito +rizo +roble +roce +rociar +rodar +rodeo +rodilla +roer +rojizo +rojo +romero +romper +ron +ronco +ronda +ropa +ropero +rosa +rosca +rostro +rotar +rubí +rubor +rudo +rueda +rugir +ruido +ruina +ruleta +rulo +rumbo +rumor +ruptura +ruta +rutina +sábado +saber +sabio +sable +sacar +sagaz +sagrado +sala +saldo +salero +salir +salmón +salón +salsa +salto +salud +salvar +samba +sanción +sandía +sanear +sangre +sanidad +sano +santo +sapo +saque +sardina +sartén +sastre +satán +sauna +saxofón +sección +seco +secreto +secta +sed +seguir +seis +sello +selva +semana +semilla +senda +sensor +señal +señor +separar +sepia +sequía +ser +serie +sermón +servir +sesenta +sesión +seta +setenta +severo +sexo +sexto +sidra +siesta +siete +siglo +signo +sílaba +silbar +silencio +silla +símbolo +simio +sirena +sistema +sitio +situar +sobre +socio +sodio +sol +solapa +soldado +soledad +sólido +soltar +solución +sombra +sondeo +sonido +sonoro +sonrisa +sopa +soplar +soporte +sordo +sorpresa +sorteo +sostén +sótano +suave +subir +suceso +sudor +suegra +suelo +sueño +suerte +sufrir +sujeto +sultán +sumar +superar +suplir +suponer +supremo +sur +surco +sureño +surgir +susto +sutil +tabaco +tabique +tabla +tabú +taco +tacto +tajo +talar +talco +talento +talla +talón +tamaño +tambor +tango +tanque +tapa +tapete +tapia +tapón +taquilla +tarde +tarea +tarifa +tarjeta +tarot +tarro +tarta +tatuaje +tauro +taza +tazón +teatro +techo +tecla +técnica +tejado +tejer +tejido +tela +teléfono +tema +temor +templo +tenaz +tender +tener +tenis +tenso +teoría +terapia +terco +término +ternura +terror +tesis +tesoro +testigo +tetera +texto +tez +tibio +tiburón +tiempo +tienda +tierra +tieso +tigre +tijera +tilde +timbre +tímido +timo +tinta +tío +típico +tipo +tira +tirón +titán +títere +título +tiza +toalla +tobillo +tocar +tocino +todo +toga +toldo +tomar +tono +tonto +topar +tope +toque +tórax +torero +tormenta +torneo +toro +torpedo +torre +torso +tortuga +tos +tosco +toser +tóxico +trabajo +tractor +traer +tráfico +trago +traje +tramo +trance +trato +trauma +trazar +trébol +tregua +treinta +tren +trepar +tres +tribu +trigo +tripa +triste +triunfo +trofeo +trompa +tronco +tropa +trote +trozo +truco +trueno +trufa +tubería +tubo +tuerto +tumba +tumor +túnel +túnica +turbina +turismo +turno +tutor +ubicar +úlcera +umbral +unidad +unir +universo +uno +untar +uña +urbano +urbe +urgente +urna +usar +usuario +útil +utopía +uva +vaca +vacío +vacuna +vagar +vago +vaina +vajilla +vale +válido +valle +valor +válvula +vampiro +vara +variar +varón +vaso +vecino +vector +vehículo +veinte +vejez +vela +velero +veloz +vena +vencer +venda +veneno +vengar +venir +venta +venus +ver +verano +verbo +verde +vereda +verja +verso +verter +vía +viaje +vibrar +vicio +víctima +vida +vídeo +vidrio +viejo +viernes +vigor +vil +villa +vinagre +vino +viñedo +violín +viral +virgo +virtud +visor +víspera +vista +vitamina +viudo +vivaz +vivero +vivir +vivo +volcán +volumen +volver +voraz +votar +voto +voz +vuelo +vulgar +yacer +yate +yegua +yema +yerno +yeso +yodo +yoga +yogur +zafiro +zanja +zapato +zarza +zona +zorro +zumo +zurdo diff --git a/src/test/java/com/syntifi/crypto/key/AbstractCryptoTests.java b/src/test/java/com/syntifi/crypto/key/AbstractCryptoTests.java new file mode 100644 index 000000000..0001df3f1 --- /dev/null +++ b/src/test/java/com/syntifi/crypto/key/AbstractCryptoTests.java @@ -0,0 +1,72 @@ +package com.syntifi.crypto.key; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.net.URISyntaxException; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Objects; + +/** + * Shared key testing functionality + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.1.0 + */ +public abstract class AbstractCryptoTests { + /** + * Loads test key file from resources + * + * @param filename the file name + * @return a string with file path from resources + * @throws URISyntaxException thrown if it can't parse file url to URI for fetching the path + */ + protected String getResourcesKeyPath(String filename) throws URISyntaxException { + return Paths.get(Objects.requireNonNull(getClass().getClassLoader().getResource(filename)).toURI()).toString(); + } + + /** + * Compare text files + * + * @param file1 a file object + * @param file2 another file object + * @return true if matches, false otherwise + * @throws IOException thrown if error reading files + */ + protected boolean compareTextFiles(File file1, File file2) throws IOException { + byte[] contentFile1 = Files.readAllBytes(file1.toPath()); + byte[] contentFile2 = Files.readAllBytes(file2.toPath()); + + return Arrays.equals(contentFile1, contentFile2); + } + + /** + * @param file1 a file + * @param file2 another file + * @return true if matches, false otherwise + * @throws IOException thrown if error reading files + */ + protected boolean compareFiles(File file1, File file2) throws IOException { + try (RandomAccessFile randomAccessFile1 = new RandomAccessFile(file1, "r"); + RandomAccessFile randomAccessFile2 = new RandomAccessFile(file2, "r")) { + + FileChannel ch1 = randomAccessFile1.getChannel(); + FileChannel ch2 = randomAccessFile2.getChannel(); + + if (ch1.size() != ch2.size()) { + return false; + } + + long size = ch1.size(); + MappedByteBuffer m1 = ch1.map(FileChannel.MapMode.READ_ONLY, 0L, size); + MappedByteBuffer m2 = ch2.map(FileChannel.MapMode.READ_ONLY, 0L, size); + + return m1.equals(m2); + } + } +} diff --git a/src/test/java/com/syntifi/crypto/key/Ed25519PrivateKeyTests.java b/src/test/java/com/syntifi/crypto/key/Ed25519PrivateKeyTests.java new file mode 100644 index 000000000..28756e8dd --- /dev/null +++ b/src/test/java/com/syntifi/crypto/key/Ed25519PrivateKeyTests.java @@ -0,0 +1,128 @@ +package com.syntifi.crypto.key; + +import com.syntifi.crypto.key.deterministic.HierarchicalDeterministicKey; +import com.syntifi.crypto.key.encdec.Base58; +import com.syntifi.crypto.key.encdec.Hex; +import com.syntifi.crypto.key.mnemonic.Language; +import com.syntifi.crypto.key.mnemonic.MnemonicCode; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests for {@link Ed25519PrivateKey} + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.1.0 + */ +public class Ed25519PrivateKeyTests extends AbstractCryptoTests { + private static final Logger LOGGER = LoggerFactory.getLogger(Ed25519PrivateKeyTests.class); + + @Test + void readPrivateKey_should_load_private_key() throws IOException, URISyntaxException { + Ed25519PrivateKey privateKey = readPrivateKey("ed25519/secret_key.pem"); + assertNotNull(privateKey.getKey()); + } + + @Test + void readPrivateKey_derived_public_key_should_equal_generated() throws IOException, URISyntaxException { + Ed25519PrivateKey privateKey = readPrivateKey("ed25519/secret_key.pem"); + + // Compare derived public key to generated hex without leading id byte + Path hexKeyFilePath = Paths.get(getResourcesKeyPath("ed25519/public_key_hex")); + String hexKey = new String(Files.readAllBytes(hexKeyFilePath)); + LOGGER.debug("Derived public hex Key from {}: {}", hexKeyFilePath, + Hex.encode(privateKey.derivePublicKey().getKey())); + + assertEquals(hexKey.substring(2), Hex.encode(privateKey.derivePublicKey().getKey())); + } + + @Test + void writePrivateKey_should_equal_source_file() throws URISyntaxException, IOException { + Ed25519PrivateKey privateKey = readPrivateKey("ed25519/secret_key.pem"); + + DateFormat df = new SimpleDateFormat("yyyyMMdd-HHmmss"); + File privateKeyFile = File.createTempFile(df.format(new Date()), "-private-key-test.pem"); + + LOGGER.debug("Writing private key to {}", privateKeyFile.getPath()); + privateKey.writePrivateKey(privateKeyFile.getPath()); + + assertTrue(compareTextFiles(new File(getResourcesKeyPath("ed25519/secret_key.pem")), + privateKeyFile)); + } + + @Test + void sign_should_sign_message() throws URISyntaxException, IOException { + Ed25519PrivateKey privateKey = readPrivateKey("ed25519/secret_key.pem"); + + byte[] signature = privateKey.sign("Test message".getBytes()); + + assertEquals( + "4555103678684364a98478112ce0c298ed841d806d2b67b09e8f0215cc738f3c5a1fca5beaf0474ff636613821bcb97e88b3b4d700e65c6cf7574489e09f170c", + Hex.encode(signature)); + + LOGGER.debug("Signed as {}", signature); + } + + @Test + void derived_public_key_should_match_generated() { + String base58GeneratedPrivateKey = "32UfEkBGTFpfu6M7RebN1JqMDrdf1YyztgYmcUG5XcRkEraJioFZLPtBvYVmAVvnjWAToSsWScJYSFViv8MaATRF"; + String base58GeneratedPublicKey = "F8jARHGZdHqnwrxrnv1pFVzzirXZR2vJzeYbvwQbxZyP"; + + Ed25519PrivateKey pk = new Ed25519PrivateKey(Base58.decode(base58GeneratedPrivateKey)); + + assertEquals(base58GeneratedPublicKey, Base58.encode(pk.derivePublicKey().getKey())); + } + + @Test + void create_privateKey_from_seed() throws IOException { + MnemonicCode mnemonicCode = new MnemonicCode(Language.EN); + String words = "shoot island position soft burden budget tooth cruel issue economy destroy above"; + byte[] seed = mnemonicCode.toSeed(Arrays.asList(words.split(" ")), ""); + int[] path = {44, 397, 0}; + + Ed25519PrivateKey pk1 = Ed25519PrivateKey.deriveFromSeed(seed, path); + byte[] init = "ed25519 seed".getBytes(StandardCharsets.UTF_8); + byte[] key = HierarchicalDeterministicKey.getFromSeed(seed, init, path); + Ed25519PrivateKey pk2 = new Ed25519PrivateKey(key); + assertEquals("88793a8eeec537c67ee8d459f1899a47a2f1b752d06a4c793c66fd751df8049838d300841c903867050c222b9f0b43893a5675f0a87756cfce4e3fd71c23334a", + Hex.encode(pk1.getKey())); + assertEquals(Hex.encode(pk2.getKey()), Hex.encode(pk1.getKey())); + assertEquals("0c91f6106ff835c0195d5388565a2d69e25038a7e23d26198f85caf6594117ec", + Hex.encode(pk1.derivePublicKey().getKey())); + assertEquals(Hex.encode(pk2.derivePublicKey().getKey()), Hex.encode(pk1.derivePublicKey().getKey())); + } + + @Test + void create_random_key() { + Ed25519PrivateKey sk = Ed25519PrivateKey.deriveRandomKey(); + Ed25519PublicKey pk = (Ed25519PublicKey) sk.derivePublicKey(); + byte[] msg = "this is a test".getBytes(); + byte[] signature = sk.sign(msg); + assertTrue(pk.verify(msg, signature)); + } + + private Ed25519PrivateKey readPrivateKey(String privateKeyPath) throws URISyntaxException, IOException { + Ed25519PrivateKey privateKey = new Ed25519PrivateKey(); + String keyFilePath = getResourcesKeyPath(privateKeyPath); + LOGGER.debug("Reading key from {}", keyFilePath); + privateKey.readPrivateKey(keyFilePath); + LOGGER.debug("Key: {}", Hex.encode(privateKey.getKey())); + return privateKey; + } +} diff --git a/src/test/java/com/syntifi/crypto/key/Ed25519PublicKeyTests.java b/src/test/java/com/syntifi/crypto/key/Ed25519PublicKeyTests.java new file mode 100644 index 000000000..a73b064b9 --- /dev/null +++ b/src/test/java/com/syntifi/crypto/key/Ed25519PublicKeyTests.java @@ -0,0 +1,82 @@ +package com.syntifi.crypto.key; + +import com.syntifi.crypto.key.encdec.Hex; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests for {@link Ed25519PublicKey} + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.1.0 + */ +public class Ed25519PublicKeyTests extends AbstractCryptoTests { + private static final Logger LOGGER = LoggerFactory.getLogger(Ed25519PublicKeyTests.class); + + @Test + void readPublicKey_should_load_and_be_equal_to_generated_public_key() throws IOException, URISyntaxException { + Ed25519PublicKey publicKey = loadPublicKey("ed25519/public_key.pem"); + assertNotNull(publicKey.getKey()); + + // Compare to generated hex without leading id byte + Path hexKeyFilePath = Paths.get(getResourcesKeyPath("ed25519/public_key_hex")); + String hexKey = new String(Files.readAllBytes(hexKeyFilePath)); + LOGGER.debug("Hex Key from {}: {}", hexKeyFilePath, Hex.encode(publicKey.getKey())); + assertEquals(hexKey.substring(2), Hex.encode(publicKey.getKey())); + } + + @Test + void writePublicKey_should_equal_source_file() throws URISyntaxException, IOException { + Ed25519PublicKey publicKey = loadPublicKey("ed25519/public_key.pem"); + + DateFormat df = new SimpleDateFormat("yyyyMMdd-HHmmss"); + File publicKeyFile = File.createTempFile(df.format(new Date()), "-public-key-test.pem"); + + LOGGER.debug("Writing public key to {}", publicKeyFile.getPath()); + publicKey.writePublicKey(publicKeyFile.getPath()); + + assertTrue(compareTextFiles(new File(getResourcesKeyPath("ed25519/public_key.pem")), + publicKeyFile)); + } + + @Test + void verify_should_work_with_previously_signed_message() throws URISyntaxException, IOException { + String message = "Test message"; + String hexSignature = "4555103678684364a98478112ce0c298ed841d806d2b67b09e8f0215cc738f3c5a1fca5beaf0474ff636613821bcb97e88b3b4d700e65c6cf7574489e09f170c"; + + Ed25519PublicKey publicKey = loadPublicKey("ed25519/public_key.pem"); + + String hexKey = Hex.encode(publicKey.getKey()); + + LOGGER.debug("Verifying Ed25519 signature of {} with key {}", message, hexKey); + + Boolean verified = publicKey.verify(message.getBytes(), Hex.decode(hexSignature)); + + LOGGER.debug("Signature verified: {}", verified); + + assertTrue(verified); + } + + private Ed25519PublicKey loadPublicKey(String publicKeyPath) throws URISyntaxException, IOException { + Ed25519PublicKey publicKey = new Ed25519PublicKey(); + String keyFilePath = getResourcesKeyPath(publicKeyPath); + LOGGER.debug("Reading key from {}", keyFilePath); + publicKey.readPublicKey(keyFilePath); + LOGGER.debug("Key: {}", Hex.encode(publicKey.getKey())); + return publicKey; + } +} diff --git a/src/test/java/com/syntifi/crypto/key/Secp256k1PrivateKeyTests.java b/src/test/java/com/syntifi/crypto/key/Secp256k1PrivateKeyTests.java new file mode 100644 index 000000000..2852c952f --- /dev/null +++ b/src/test/java/com/syntifi/crypto/key/Secp256k1PrivateKeyTests.java @@ -0,0 +1,96 @@ +package com.syntifi.crypto.key; + +import com.syntifi.crypto.key.encdec.Hex; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.security.GeneralSecurityException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests for {@link Secp256k1PrivateKey} + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.1.0 + */ +public class Secp256k1PrivateKeyTests extends AbstractCryptoTests { + private static final Logger LOGGER = LoggerFactory.getLogger(Secp256k1PublicKeyTests.class); + + @Test + void readPrivateKey_should_load_private_key() throws URISyntaxException, IOException { + Secp256k1PrivateKey privKey = new Secp256k1PrivateKey(); + String filePath = getResourcesKeyPath("secp256k1/secret_key.pem"); + privKey.readPrivateKey(filePath); + + assertNotNull(privKey.getKey()); + } + + @Test + void writePrivateKey_should_equal_source_file() throws URISyntaxException, IOException { + Secp256k1PrivateKey privKey = new Secp256k1PrivateKey(); + String filePath = getResourcesKeyPath("secp256k1/secret_key.pem"); + privKey.readPrivateKey(filePath); + + DateFormat df = new SimpleDateFormat("yyyyMMdd-HHmmss"); + File privateKeyFile = File.createTempFile(df.format(new Date()), "-secret-key-test.pem"); + privKey.writePrivateKey(privateKeyFile.getPath()); + + assertTrue(compareTextFiles(new File(getResourcesKeyPath("secp256k1/secret_key.pem")), + privateKeyFile)); + } + + @Test + void readPrivateKey_derived_public_key_should_equal_generated() throws URISyntaxException, IOException { + Secp256k1PrivateKey privKey = new Secp256k1PrivateKey(); + String filePath = getResourcesKeyPath("secp256k1/secret_key.pem"); + privKey.readPrivateKey(filePath); + Secp256k1PublicKey pubKey = (Secp256k1PublicKey) privKey.derivePublicKey(); + + DateFormat df = new SimpleDateFormat("yyyyMMdd-HHmmss"); + File derivedPublicKeyFile = File.createTempFile(df.format(new Date()), "-derived-public-key-test.pem"); + pubKey.writePublicKey(derivedPublicKeyFile.getPath()); + LOGGER.info(privKey.getKeyPair().getPrivateKey().toString(16)); + LOGGER.info(privKey.getKeyPair().getPublicKey().toString(16)); + LOGGER.info(Hex.encode(pubKey.getKey())); + assertTrue(compareTextFiles(new File(getResourcesKeyPath("secp256k1/public_key.pem")), + derivedPublicKeyFile)); + } + + @Test + void sign_should_sign_message() throws URISyntaxException, IOException { + Secp256k1PrivateKey privKey = new Secp256k1PrivateKey(); + String filePath = getResourcesKeyPath("secp256k1/secret_key.pem"); + privKey.readPrivateKey(filePath); + LOGGER.info(privKey.getKeyPair().getPublicKey().toString(16)); + LOGGER.info(Hex.encode(privKey.getKey())); + + byte[] signature = privKey.sign("Test message".getBytes()); + + LOGGER.info(Hex.encode(signature)); + assertEquals( + "ea5b38fd0db5fb3d871c47fde1fa4c4db75d1a9e1c0ac54d826e178ee0e63707176b4e63b4f838bd031f007fffd6a4f71d920a10c48ea53dd1573fa2b58a829e", + Hex.encode(signature)); + } + + @Test + void create_random_key() throws GeneralSecurityException, IOException { + Secp256k1PrivateKey sk = Secp256k1PrivateKey.deriveRandomKey(); + Secp256k1PublicKey pk = (Secp256k1PublicKey) sk.derivePublicKey(); + LOGGER.info(sk.getKeyPair().getPrivateKey().toString(16)); + LOGGER.info(sk.getKeyPair().getPublicKey().toString(16)); + LOGGER.info(Hex.encode(pk.getKey())); + byte[] msg = "this is a test".getBytes(); + byte[] signature = sk.sign(msg); + LOGGER.info(Hex.encode(signature)); + assertTrue(pk.verify(msg, signature)); + } +} diff --git a/src/test/java/com/syntifi/crypto/key/Secp256k1PublicKeyTests.java b/src/test/java/com/syntifi/crypto/key/Secp256k1PublicKeyTests.java new file mode 100644 index 000000000..74a6672c2 --- /dev/null +++ b/src/test/java/com/syntifi/crypto/key/Secp256k1PublicKeyTests.java @@ -0,0 +1,63 @@ +package com.syntifi.crypto.key; + +import com.syntifi.crypto.key.encdec.Hex; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.security.GeneralSecurityException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Tests for {@link Secp256k1PublicKey} + * + * @author Alexandre Carvalho + * @author Andre Bertolace + * @since 0.1.0 + */ +public class Secp256k1PublicKeyTests extends AbstractCryptoTests { + private static final Logger LOGGER = LoggerFactory.getLogger(Secp256k1PublicKeyTests.class); + + @Test + void readPublicKey_should_load_public_key() throws IOException, URISyntaxException { + Secp256k1PublicKey pubKey = new Secp256k1PublicKey(); + String filePath = getResourcesKeyPath("secp256k1/public_key.pem"); + pubKey.readPublicKey(filePath); + + assertNotNull(pubKey.getKey()); + } + + @Test + void writePublicKey_should_equal_source_file() throws URISyntaxException, IOException { + Secp256k1PublicKey pubKey = new Secp256k1PublicKey(); + String filePath = getResourcesKeyPath("secp256k1/public_key.pem"); + pubKey.readPublicKey(filePath); + + DateFormat df = new SimpleDateFormat("yyyyMMdd-HHmmss"); + File publicKeyFile = File.createTempFile(df.format(new Date()), "-public-key-test.pem"); + pubKey.writePublicKey(publicKeyFile.getPath()); + + assertTrue(compareTextFiles(new File(getResourcesKeyPath("secp256k1/public_key.pem")), + publicKeyFile)); + } + + @Test + void verify_should_be_ok() throws URISyntaxException, IOException, GeneralSecurityException { + String hexSignature = "ea5b38fd0db5fb3d871c47fde1fa4c4db75d1a9e1c0ac54d826e178ee0e63707176b4e63b4f838bd031f007fffd6a4f71d920a10c48ea53dd1573fa2b58a829e"; + + Secp256k1PublicKey pubKey = new Secp256k1PublicKey(); + String filePath = getResourcesKeyPath("secp256k1/public_key.pem"); + pubKey.readPublicKey(filePath); + LOGGER.info(Hex.encode(pubKey.getKey())); + + assertTrue(pubKey.verify("Test message".getBytes(), Hex.decode(hexSignature))); + } +} \ No newline at end of file diff --git a/src/test/java/com/syntifi/crypto/key/checksum/MixedCaseChecksumTest.java b/src/test/java/com/syntifi/crypto/key/checksum/MixedCaseChecksumTest.java new file mode 100644 index 000000000..0a8b06871 --- /dev/null +++ b/src/test/java/com/syntifi/crypto/key/checksum/MixedCaseChecksumTest.java @@ -0,0 +1,38 @@ +package com.syntifi.crypto.key.checksum; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class MixedCaseChecksumTest { + + @Test + void eip55ShouldMatchLowerCaseAddress() { + assertEquals("fB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", + MixedCaseChecksum.checksumEncodeEIP55("fb6916095ca1df60bb79ce92ce3ea74c37c5d359")); + } + + @Test + void eip55ShouldMatchUpperCaseAddress() { + assertEquals("fB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", + MixedCaseChecksum.checksumEncodeEIP55("FB6916095CA1DF60BB79CE92CE3EA74C37C5D359")); + } + + @Test + void cep57houldMatchEmptyAddress() { + assertEquals("", + MixedCaseChecksum.checksumEncodeEIP55("")); + } + @Test + void cep57houldMatchLowerCaseAddress() { + assertEquals("010573D52dFA032716fDC2AE5396987f280304106fC11f6Ac6Ccf287B81dc09ED7", + MixedCaseChecksum.checksumEncodeCEP57("010573d52dfa032716fdc2ae5396987f280304106fc11f6ac6ccf287b81dc09ed7")); + } + + @Test + void cep57houldMatchUpperCaseAddress() { + assertEquals("51DA5aE5C39880Bfe4f94B0898332d1BD37e647F72f79Cf23475df1Bb1f85bEA", + MixedCaseChecksum.checksumEncodeCEP57("51da5ae5c39880bfe4f94b0898332d1bd37e647f72f79cf23475df1bb1f85bea")); + } + +} diff --git a/src/test/java/com/syntifi/crypto/key/deterministic/HierarchicalDeterministicKeyTest.java b/src/test/java/com/syntifi/crypto/key/deterministic/HierarchicalDeterministicKeyTest.java new file mode 100644 index 000000000..7cac1b814 --- /dev/null +++ b/src/test/java/com/syntifi/crypto/key/deterministic/HierarchicalDeterministicKeyTest.java @@ -0,0 +1,45 @@ +package com.syntifi.crypto.key.deterministic; + +import com.syntifi.crypto.key.encdec.Hex; +import com.syntifi.crypto.key.mnemonic.Language; +import com.syntifi.crypto.key.mnemonic.MnemonicCode; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class HierarchicalDeterministicKeyTest { + private static final Logger LOGGER = LoggerFactory.getLogger(HierarchicalDeterministicKey.class); + + + @Test + void getMasterKeyFromSeed_seed_should_match() { + byte[] init = "ed25519 seed".getBytes(StandardCharsets.UTF_8); + assertEquals("a89c4655ab993cf786e4a8517899f0e5ddbdb35ebedc05da341b510bf0c5b8902eb38e1fb071b5a75f0e3b176ddea874ce81fafd6c44cd74c3c381ac5a7ed9fc", + Hex.encode(HierarchicalDeterministicKey.getMasterKeyFromSeed( + "randomkey".getBytes(StandardCharsets.UTF_8), init))); + } + + @Test + void getKeyFromSeed_seed_should_match() throws IOException { + MnemonicCode mnemonicCode = new MnemonicCode(Language.EN); + String words = "shoot island position soft burden budget tooth cruel issue economy destroy above"; + byte[] seed = mnemonicCode.toSeed(Arrays.asList(words.split(" ")), ""); + assertEquals("577cd910aede2582668a741d476b45e7998e905a4286f701b87b25923501f9d4ea19513b460bcccbc069ebbe4327a59af3d6463045c4b6fa21a5e7004ccfcc3e", + Hex.encode(seed)); + byte[] init = "ed25519 seed".getBytes(StandardCharsets.UTF_8); + assertEquals("17ffa27bec941a557d88ef8d491171eab1dcb147b24b8c7f034766b5a2c425ab" + + "6f1eef3d85f72c2500f3d42cad8632725e830d20ffa61d8dfda1c961c84302f0", + Hex.encode(HierarchicalDeterministicKey.getMasterKeyFromSeed(seed, init))); + int[] path = {44, 397, 0}; + assertEquals("88793a8eeec537c67ee8d459f1899a47a2f1b752d06a4c793c66fd751df8049838d300841c903867050c222b9f0b43893a5675f0a87756cfce4e3fd71c23334a", + Hex.encode(HierarchicalDeterministicKey.getFromSeed(seed, init, path))); + assertTrue(true); + } +} diff --git a/src/test/java/com/syntifi/crypto/key/encdec/Base58Test.java b/src/test/java/com/syntifi/crypto/key/encdec/Base58Test.java new file mode 100644 index 000000000..2da2e67b6 --- /dev/null +++ b/src/test/java/com/syntifi/crypto/key/encdec/Base58Test.java @@ -0,0 +1,22 @@ +package com.syntifi.crypto.key.encdec; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class Base58Test { + @Test + void bs58() { + String expected = "16UjcYNBG9GTK4uq2f7yYEbuifqCzoLMGS"; + byte[] bytes = new byte[]{ + 0, 60, 23, 110, 101, (byte) 155, (byte) 234, + 15, 41, (byte) 163, (byte) 233, (byte) 191, 120, (byte) 128, + (byte) 193, 18, (byte) 177, (byte) 179, 27, 77, (byte) 200, + 38, 38, (byte) 129, (byte) 135 + }; + + assertEquals(expected, Base58.encode(bytes)); + assertArrayEquals(Base58.decode(expected), bytes); + } +} \ No newline at end of file diff --git a/src/test/java/com/syntifi/crypto/key/hash/Blake2bTest.java b/src/test/java/com/syntifi/crypto/key/hash/Blake2bTest.java new file mode 100644 index 000000000..041c4e9cf --- /dev/null +++ b/src/test/java/com/syntifi/crypto/key/hash/Blake2bTest.java @@ -0,0 +1,16 @@ +package com.syntifi.crypto.key.hash; + +import com.syntifi.crypto.key.encdec.Hex; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; + +public class Blake2bTest { + + @Test + void test() { + Assertions.assertEquals("44682ea86b704fb3c65cd16f84a76b621e04bbdb3746280f25cf062220e471b4", + Hex.encode(Blake2b.digest("أبو يوسف يعقوب بن إسحاق الصبّاح الكندي‎".getBytes(StandardCharsets.UTF_8), 32))); + } +} diff --git a/src/test/java/com/syntifi/crypto/key/hash/Keccak256Test.java b/src/test/java/com/syntifi/crypto/key/hash/Keccak256Test.java new file mode 100644 index 000000000..114637b3f --- /dev/null +++ b/src/test/java/com/syntifi/crypto/key/hash/Keccak256Test.java @@ -0,0 +1,14 @@ +package com.syntifi.crypto.key.hash; + +import com.syntifi.crypto.key.encdec.Hex; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class Keccak256Test { + + @Test + void kekkac256ShouldMatch() { + Assertions.assertEquals("a9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b", + Hex.encode(Keccak256.digest("transfer(address,uint256)".getBytes()))); + } +} diff --git a/src/test/java/com/syntifi/crypto/key/mnemonic/MnemonicCodeTest.java b/src/test/java/com/syntifi/crypto/key/mnemonic/MnemonicCodeTest.java new file mode 100644 index 000000000..c66f2738a --- /dev/null +++ b/src/test/java/com/syntifi/crypto/key/mnemonic/MnemonicCodeTest.java @@ -0,0 +1,105 @@ +package com.syntifi.crypto.key.mnemonic; + +import com.syntifi.crypto.key.AbstractCryptoTests; +import com.syntifi.crypto.key.encdec.Hex; +import com.syntifi.crypto.key.mnemonic.exception.MnemonicException; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * examples at + * https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch05.asciidoc#creating-an-hd-wallet-from-the-seed + * + * comparing with the output from + * https://iancoleman.io/bip39/ + */ +public class MnemonicCodeTest extends AbstractCryptoTests { + private static final Logger LOGGER = LoggerFactory.getLogger(MnemonicCodeTest.class); + + @Test + void getSeedFromWordlist_seed_should_match() throws IOException, MnemonicException.MnemonicWordException, MnemonicException.MnemonicChecksumException, MnemonicException.MnemonicLengthException { + String words = "army van defense carry jealous true garbage claim echo media make crunch"; + List wordList = Arrays.asList(words.split(" ")); + MnemonicCode mnemonicCode = new MnemonicCode(Language.EN); + byte[] seed = mnemonicCode.toSeed(wordList, ""); + assertEquals("5b56c417303faa3fcba7e57400e120a0ca83ec5a4fc9ffba757fbe63fbd77a89a1a3be4c67196f57c39a88b76373733891bfaba16ed27a813ceed498804c0570", Hex.encode(seed)); + } + + @Test + void getEntropyFromWordlist_entropy_should_match() throws IOException, MnemonicException.MnemonicWordException, MnemonicException.MnemonicChecksumException, MnemonicException.MnemonicLengthException { + String words = "army van defense carry jealous true garbage claim echo media make crunch"; + List wordList = Arrays.asList(words.split(" ")); + MnemonicCode mnemonicCode = new MnemonicCode(Language.EN); + byte[] entropy = mnemonicCode.toEntropy(wordList); + assertEquals("0c1e24e5917779d297e14d45f14e1a1a", Hex.encode(entropy)); + } + + @Test + void getWordListFromEntropy_words_should_match() throws IOException, MnemonicException.MnemonicWordException, MnemonicException.MnemonicChecksumException, MnemonicException.MnemonicLengthException { + MnemonicCode mnemonicCode = new MnemonicCode(Language.EN); + List w = mnemonicCode.toMnemonic(Hex.decode("0c1e24e5917779d297e14d45f14e1a1a")); + String words = "army van defense carry jealous true garbage claim echo media make crunch"; + List wordList = Arrays.asList(words.split(" ")); + assertEquals(w, wordList); + } + + @Test + void generateRandomList_should_generate_12_words() throws IOException, MnemonicException.MnemonicWordException, MnemonicException.MnemonicChecksumException, MnemonicException.MnemonicLengthException { + MnemonicCode mnemonicCode = new MnemonicCode(Language.EN); + List words = mnemonicCode.generateSecureRandomWords(); + assertEquals(12, words.size()); + } + + @Test + void getEntropyAndSeedFromWordlistPT_entropy_should_match() throws IOException, MnemonicException.MnemonicWordException, MnemonicException.MnemonicChecksumException, MnemonicException.MnemonicLengthException { + String words = "alfinete trilogia citar berro graveto teimar evacuar broa debitar jurista irritado cerrado"; + List wordList = Arrays.asList(words.split(" ")); + MnemonicCode mnemonicCode = new MnemonicCode(Language.PT); + byte[] entropy = mnemonicCode.toEntropy(wordList); + assertEquals("0c1e24e5917779d297e14d45f14e1a1a", Hex.encode(entropy)); + byte[] seed = mnemonicCode.toSeed(wordList, ""); + assertEquals("0d2d2982b58e3faf152b5e3276198829bea74db45fdbce7fa8f2e2e5c2ac8cd0f634bc35e33960456d09299af65763b7c094ea52c88f60cbb37251c067c6a9f4", Hex.encode(seed)); + } + + @Test + void getEntropyAndSeedFromWordlistFR_entropy_should_match() throws IOException, MnemonicException.MnemonicWordException, MnemonicException.MnemonicChecksumException, MnemonicException.MnemonicLengthException { + String words = "amour troupeau couteau brèche gustatif tenaille exécuter capuche dicter lagune jaune cogner"; + List wordList = Arrays.asList(words.split(" ")); + MnemonicCode mnemonicCode = new MnemonicCode(Language.FR); + byte[] entropy = mnemonicCode.toEntropy(wordList); + assertEquals("0c1e24e5917779d297e14d45f14e1a1a", Hex.encode(entropy)); + byte[] seed = mnemonicCode.toSeed(wordList, ""); + assertEquals("895debca7a86928a0c4cb5712aefd6d4cf4c7cfd23448ccd5418932e4f00c940089a3501f4f33eaf115f1a689d6c1e54b6bb6d5f40e4791234cb2ac87d62df68", Hex.encode(seed)); + } + + @Test + void getEntropyAndSeedFromWordlistES_entropy_should_match() throws IOException, MnemonicException.MnemonicWordException, MnemonicException.MnemonicChecksumException, MnemonicException.MnemonicLengthException { + String words = "amistad túnica costa broma juicio toalla furgón caña domingo masivo maldad código"; + List wordList = Arrays.asList(words.split(" ")); + MnemonicCode mnemonicCode = new MnemonicCode(Language.ES); + byte[] entropy = mnemonicCode.toEntropy(wordList); + assertEquals("0c1e24e5917779d297e14d45f14e1a1a", Hex.encode(entropy)); + byte[] seed = mnemonicCode.toSeed(wordList, ""); + assertEquals("847ebfae3823c7ebf1cb2e8313774784751f554bd6c772c4966a860920852f4e96a058f191b0140a3190ca2d47e7766cfa69aae9a2a44b457ef86df1336e6847", Hex.encode(seed)); + } + +/*TODO: Chinese + @Test + void getEntropyAndSeedFromWordlistCNSimplified_entropy_should_match() throws IOException, MnemonicException.MnemonicWordException, MnemonicException.MnemonicChecksumException, MnemonicException.MnemonicLengthException { + String words = "点 挡 眼 器 哥 舒 久 示 止 累 夏 便"; + List wordList = Arrays.asList(words.split(" ")); + MnemonicCode mnemonicCode = new MnemonicCode(Language.CNS); + byte[] entropy = mnemonicCode.toEntropy(wordList); + assertEquals("0c1e24e5917779d297e14d45f14e1a1a", Hex.encode(entropy)); + byte[] seed = mnemonicCode.toSeed(wordList, ""); + assertEquals("ca43a6850c4dc61c05d487224e827cc9b5bcab49fd28a206bcf19f11c39d9dd4329e55e33940ae551b9fa295c9b73770c77d878fd63dc000b3995f4dc62f3f63", Hex.encode(seed)); + } +*/ +} diff --git a/src/test/resources/ed25519/public_key.pem b/src/test/resources/ed25519/public_key.pem new file mode 100644 index 000000000..1305d7057 --- /dev/null +++ b/src/test/resources/ed25519/public_key.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAMvrHQK2XpoIhUSeEhwSGXW0zAViqtNYUQ52r/7LsvjY= +-----END PUBLIC KEY----- diff --git a/src/test/resources/ed25519/public_key_hex b/src/test/resources/ed25519/public_key_hex new file mode 100644 index 000000000..50b1e0e3a --- /dev/null +++ b/src/test/resources/ed25519/public_key_hex @@ -0,0 +1 @@ +0132fac740ad97a682215127848704865d6d330158aab4d614439dabffb2ecbe36 \ No newline at end of file diff --git a/src/test/resources/ed25519/secret_key.pem b/src/test/resources/ed25519/secret_key.pem new file mode 100644 index 000000000..9776294ea --- /dev/null +++ b/src/test/resources/ed25519/secret_key.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIEb1trdv9YzoExEUjPDl1XEgdD+AZX6gGtgGZO4k6MBd +-----END PRIVATE KEY----- diff --git a/src/test/resources/secp256k1/public_key.pem b/src/test/resources/secp256k1/public_key.pem new file mode 100644 index 000000000..21af35019 --- /dev/null +++ b/src/test/resources/secp256k1/public_key.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MDYwEAYHKoZIzj0CAQYFK4EEAAoDIgADDfbouWROtMFMsD1StqFjNmrKgvo/dg5o +iZ4MCjMrvdo= +-----END PUBLIC KEY----- diff --git a/src/test/resources/secp256k1/public_key_hex b/src/test/resources/secp256k1/public_key_hex new file mode 100644 index 000000000..3d934a36e --- /dev/null +++ b/src/test/resources/secp256k1/public_key_hex @@ -0,0 +1 @@ +02030df6e8b9644eb4c14cb03d52b6a163366aca82fa3f760e68899e0c0a332bbdda \ No newline at end of file diff --git a/src/test/resources/secp256k1/secret_key.pem b/src/test/resources/secp256k1/secret_key.pem new file mode 100644 index 000000000..256831dba --- /dev/null +++ b/src/test/resources/secp256k1/secret_key.pem @@ -0,0 +1,3 @@ +-----BEGIN EC PRIVATE KEY----- +MC4CAQEEIAkPrgbH8BEc6g9sGdXgPp722oqB+qA2aymlKO+ObcXYoAcGBSuBBAAK +-----END EC PRIVATE KEY----- From 6f2dad8fcc09503d6ee15344bc44d4f528a09392 Mon Sep 17 00:00:00 2001 From: meywood <105049338+meywood@users.noreply.github.com> Date: Mon, 15 Apr 2024 14:19:30 +0200 Subject: [PATCH 2/7] issues/263 - import patch issues/9 and issues/11 from forked https://github.com/meywood/crypto-keys branches. --- .../exception/InvalidKeyBytesException.java | 11 ++++++++++ .../crypto/key/AbstractPrivateKey.java | 19 ++++++++++-------- .../syntifi/crypto/key/AbstractPublicKey.java | 17 ++++++++++------ .../syntifi/crypto/key/Ed25519PrivateKey.java | 20 ------------------- .../syntifi/crypto/key/Ed25519PublicKey.java | 19 ------------------ .../crypto/key/Secp256k1PrivateKey.java | 15 +------------- .../crypto/key/Secp256k1PublicKey.java | 14 ------------- .../crypto/key/Secp256k1PrivateKeyTests.java | 13 ++++++++++++ 8 files changed, 47 insertions(+), 81 deletions(-) create mode 100644 src/main/java/com/casper/sdk/exception/InvalidKeyBytesException.java diff --git a/src/main/java/com/casper/sdk/exception/InvalidKeyBytesException.java b/src/main/java/com/casper/sdk/exception/InvalidKeyBytesException.java new file mode 100644 index 000000000..b615e1756 --- /dev/null +++ b/src/main/java/com/casper/sdk/exception/InvalidKeyBytesException.java @@ -0,0 +1,11 @@ +package com.casper.sdk.exception; + +/** + * @author ian@meywood.com + */ +public class InvalidKeyBytesException extends RuntimeException { + + public InvalidKeyBytesException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/syntifi/crypto/key/AbstractPrivateKey.java b/src/main/java/com/syntifi/crypto/key/AbstractPrivateKey.java index a059949bb..d4ed373ba 100644 --- a/src/main/java/com/syntifi/crypto/key/AbstractPrivateKey.java +++ b/src/main/java/com/syntifi/crypto/key/AbstractPrivateKey.java @@ -4,9 +4,7 @@ import lombok.Data; import lombok.NoArgsConstructor; -import java.io.IOException; -import java.io.Reader; -import java.io.Writer; +import java.io.*; import java.security.GeneralSecurityException; /** @@ -36,7 +34,11 @@ public abstract class AbstractPrivateKey { * @param filename the source filename * @throws IOException thrown if an error occurs reading the file */ - public abstract void readPrivateKey(final String filename) throws IOException; + public final void readPrivateKey(final String filename) throws IOException { + try (final Reader fileReader = new FileReader(filename)) { + readPrivateKey(fileReader); + } + } /** * Reads the private key from a stream @@ -46,14 +48,17 @@ public abstract class AbstractPrivateKey { */ public abstract void readPrivateKey(final Reader reader) throws IOException; - /** * Writes the private key to a file * * @param filename the target filename * @throws IOException thrown if an error occurs writing the file */ - public abstract void writePrivateKey(final String filename) throws IOException; + public final void writePrivateKey(final String filename) throws IOException { + try (final Writer fileWriter = new FileWriter(filename)) { + writePrivateKey(fileWriter); + } + } /** * Writes the private key to a file @@ -61,10 +66,8 @@ public abstract class AbstractPrivateKey { * @param writer the target writer * @throws IOException thrown if an error occurs writing the file */ - public abstract void writePrivateKey(final Writer writer) throws IOException; - /** * Signs a message with the loaded key * diff --git a/src/main/java/com/syntifi/crypto/key/AbstractPublicKey.java b/src/main/java/com/syntifi/crypto/key/AbstractPublicKey.java index e8a5a6040..22fd2a821 100644 --- a/src/main/java/com/syntifi/crypto/key/AbstractPublicKey.java +++ b/src/main/java/com/syntifi/crypto/key/AbstractPublicKey.java @@ -4,9 +4,7 @@ import lombok.Data; import lombok.NoArgsConstructor; -import java.io.IOException; -import java.io.Reader; -import java.io.Writer; +import java.io.*; import java.security.GeneralSecurityException; /** @@ -36,7 +34,11 @@ public abstract class AbstractPublicKey { * @param filename the source filename * @throws IOException thrown if an error occurs reading the file */ - public abstract void readPublicKey(final String filename) throws IOException; + public final void readPublicKey(final String filename) throws IOException { + try (final Reader fileReader = new FileReader(filename)) { + readPublicKey(fileReader); + } + } /** * Reads the public key from a file @@ -46,14 +48,17 @@ public abstract class AbstractPublicKey { */ public abstract void readPublicKey(final Reader reader) throws IOException; - /** * Writes the public key to a file * * @param filename the target filename * @throws IOException thrown if an error occurs writing the file */ - public abstract void writePublicKey(final String filename) throws IOException; + public final void writePublicKey(final String filename) throws IOException { + try (final Writer fileWriter = new FileWriter(filename)) { + writePublicKey(fileWriter); + } + } /** * Writes the public key to a file diff --git a/src/main/java/com/syntifi/crypto/key/Ed25519PrivateKey.java b/src/main/java/com/syntifi/crypto/key/Ed25519PrivateKey.java index 511fda299..86f08aaba 100644 --- a/src/main/java/com/syntifi/crypto/key/Ed25519PrivateKey.java +++ b/src/main/java/com/syntifi/crypto/key/Ed25519PrivateKey.java @@ -41,19 +41,6 @@ public void loadPrivateKey(final byte[] privateKey) { privateKeyParameters = new Ed25519PrivateKeyParameters(privateKey, 0); } - /* - * SEQUENCE (3 elem) INTEGER 0 SEQUENCE (1 elem) OBJECT IDENTIFIER 1.3.101.112 - * curveEd25519 (EdDSA 25519 signature algorithm) OCTET STRING (32 byte) - * 38AECE974291F14B5FEF97E1B21F684394120B6E7A8AFB04398BBE787E8BC559 OCTET STRING - * (32 byte) 38AECE974291F14B5FEF97E1B21F684394120B6E7A8AFB04398BBE787E8BC559 - */ - @Override - public void readPrivateKey(final String filename) throws IOException { - try (final Reader fileReader = new FileReader(filename)) { - readPrivateKey(fileReader); - } - } - @Override public void readPrivateKey(final Reader reader) throws IOException { final ASN1Primitive key = ASN1Primitive.fromByteArray(PemFileHelper.readPemFile(reader)); @@ -65,13 +52,6 @@ public void readPrivateKey(final Reader reader) throws IOException { } } - @Override - public void writePrivateKey(final String filename) throws IOException { - try (final Writer fileWriter = new FileWriter(filename)) { - writePrivateKey(fileWriter); - } - } - @Override public void writePrivateKey(final Writer writer) throws IOException { final DERSequence derPrefix = new DERSequence(ASN1Identifiers.Ed25519OID); diff --git a/src/main/java/com/syntifi/crypto/key/Ed25519PublicKey.java b/src/main/java/com/syntifi/crypto/key/Ed25519PublicKey.java index 430dcb5fd..59706a685 100644 --- a/src/main/java/com/syntifi/crypto/key/Ed25519PublicKey.java +++ b/src/main/java/com/syntifi/crypto/key/Ed25519PublicKey.java @@ -32,18 +32,6 @@ public void loadPublicKey(final byte[] publicKey) { publicKeyParameters = new Ed25519PublicKeyParameters(publicKey, 0); } - /* - * SEQUENCE (2 elem) SEQUENCE (1 elem) OBJECT IDENTIFIER 1.3.101.112 - * curveEd25519 (EdDSA 25519 signature algorithm) BIT STRING (256 bit) - */ - @Override - public void readPublicKey(final String filename) throws IOException { - try (final Reader fileReader = new FileReader(filename)) { - readPublicKey(fileReader); - } - } - @Override public void readPublicKey(final Reader reader) throws IOException { final ASN1Primitive derKey = ASN1Primitive.fromByteArray(PemFileHelper.readPemFile(reader)); @@ -57,13 +45,6 @@ public void readPublicKey(final Reader reader) throws IOException { } } - @Override - public void writePublicKey(final String filename) throws IOException { - try (final Writer fileWriter = new FileWriter(filename)) { - writePublicKey(fileWriter); - } - } - @Override public void writePublicKey(final Writer writer) throws IOException { final DERSequence derPrefix = new DERSequence(ASN1Identifiers.Ed25519OID); diff --git a/src/main/java/com/syntifi/crypto/key/Secp256k1PrivateKey.java b/src/main/java/com/syntifi/crypto/key/Secp256k1PrivateKey.java index 8d0351a79..0e5376102 100644 --- a/src/main/java/com/syntifi/crypto/key/Secp256k1PrivateKey.java +++ b/src/main/java/com/syntifi/crypto/key/Secp256k1PrivateKey.java @@ -45,25 +45,11 @@ public void loadPrivateKey(final byte[] privateKey) throws IOException { } } - @Override - public void readPrivateKey(final String filename) throws IOException { - try (final Reader fileReader = new FileReader(filename)) { - readPrivateKey(fileReader); - } - } - @Override public void readPrivateKey(final Reader reader) throws IOException { loadPrivateKey(PemFileHelper.readPemFile(reader)); } - @Override - public void writePrivateKey(final String filename) throws IOException { - try (final FileWriter fileWriter = new FileWriter(filename)) { - writePrivateKey(fileWriter); - } - } - @Override public void writePrivateKey(final Writer writer) throws IOException { final DERTaggedObject derPrefix = new DERTaggedObject(0, ASN1Identifiers.Secp256k1OIDCurve); @@ -124,6 +110,7 @@ public static Secp256k1PrivateKey deriveRandomKey() { final ECKeyPair keyPair = ECKeyPair.create(rnd.generateSeed(32)); final Secp256k1PrivateKey sk = new Secp256k1PrivateKey(); sk.setKeyPair(keyPair); + sk.setKey(keyPair.getPrivateKey().toByteArray()); return sk; } } diff --git a/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java b/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java index 12558360b..0f7318ae4 100644 --- a/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java +++ b/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java @@ -44,25 +44,11 @@ public void loadPublicKey(final byte[] publicKey) throws IOException { } - @Override - public void readPublicKey(final String filename) throws IOException { - try (final Reader fileReader = new FileReader(filename)) { - readPublicKey(fileReader); - } - } - @Override public void readPublicKey(final Reader reader) throws IOException { loadPublicKey(PemFileHelper.readPemFile(reader)); } - @Override - public void writePublicKey(final String filename) throws IOException { - try (final FileWriter fileWriter = new FileWriter(filename)) { - writePublicKey(fileWriter); - } - } - @Override public void writePublicKey(final Writer writer) throws IOException { final DERBitString key = new DERBitString(getKey()); diff --git a/src/test/java/com/syntifi/crypto/key/Secp256k1PrivateKeyTests.java b/src/test/java/com/syntifi/crypto/key/Secp256k1PrivateKeyTests.java index 2852c952f..b62e6a0cc 100644 --- a/src/test/java/com/syntifi/crypto/key/Secp256k1PrivateKeyTests.java +++ b/src/test/java/com/syntifi/crypto/key/Secp256k1PrivateKeyTests.java @@ -93,4 +93,17 @@ void create_random_key() throws GeneralSecurityException, IOException { LOGGER.info(Hex.encode(signature)); assertTrue(pk.verify(msg, signature)); } + + @Test + void randomKeyCanBeWrittenToAndReadFromPemFile() throws IOException { + + final Secp256k1PrivateKey secp256k1PrivateKey = Secp256k1PrivateKey.deriveRandomKey(); + final File pemFile = File.createTempFile("secp256k1", ".pem"); + pemFile.deleteOnExit(); + secp256k1PrivateKey.writePrivateKey(pemFile.getPath()); + + final Secp256k1PrivateKey readKey = new Secp256k1PrivateKey(); + readKey.readPrivateKey(pemFile.getPath()); + assertEquals(Hex.encode(secp256k1PrivateKey.getKey()), Hex.encode(readKey.getKey())); + } } From 949defde5e725794143f434422945e5ea1971653 Mon Sep 17 00:00:00 2001 From: meywood <105049338+meywood@users.noreply.github.com> Date: Mon, 15 Apr 2024 14:20:10 +0200 Subject: [PATCH 3/7] issues/263 - import patch issues/9 and issues/11 from forked https://github.com/meywood/crypto-keys branches. --- src/main/java/com/syntifi/crypto/key/Secp256k1PrivateKey.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/syntifi/crypto/key/Secp256k1PrivateKey.java b/src/main/java/com/syntifi/crypto/key/Secp256k1PrivateKey.java index 0e5376102..06e13580f 100644 --- a/src/main/java/com/syntifi/crypto/key/Secp256k1PrivateKey.java +++ b/src/main/java/com/syntifi/crypto/key/Secp256k1PrivateKey.java @@ -85,8 +85,6 @@ public void writePrivateKey(final Writer writer) throws IOException { @Override public byte[] sign(final byte[] message) { final SignatureData signature = Sign.signMessage(Hash.sha256(message), keyPair, false); - // TODO: Check this conversion - //return Hex.toHexString(signature.getR()) + Hex.toHexString(signature.getS()); final ByteBuffer bb = ByteBuffer.allocate(signature.getR().length + signature.getS().length); bb.put(signature.getR()); bb.put(signature.getS()); From 09e6634bf66ba353e8526144d93d554d31738902 Mon Sep 17 00:00:00 2001 From: meywood <105049338+meywood@users.noreply.github.com> Date: Mon, 15 Apr 2024 14:46:23 +0200 Subject: [PATCH 4/7] issues/263 - import patch issues/9 and issues/11 from forked https://github.com/meywood/crypto-keys branches. --- build.gradle | 8 +++++--- gradle.properties | 14 ++++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 753ab0d10..6de857105 100644 --- a/build.gradle +++ b/build.gradle @@ -26,9 +26,11 @@ repositories { dependencies { implementation "dev.oak3:sbs4j:${sbs4jVersion}" implementation "io.github.oak:jsonrpc4j:${jsonrpc4jVersion}" - implementation "com.syntifi.crypto:crypto-key-common:${cryptokeyVersion}" - implementation "com.syntifi.crypto:crypto-key-ed25519:${cryptokeyVersion}" - implementation "com.syntifi.crypto:crypto-key-secp256k1:${cryptokeyVersion}" +// implementation "com.syntifi.crypto:crypto-key-common:${cryptokeyVersion}" +// implementation "com.syntifi.crypto:crypto-key-ed25519:${cryptokeyVersion}" +// implementation "com.syntifi.crypto:crypto-key-secp256k1:${cryptokeyVersion}" + implementation "org.bouncycastle:bcpkix-jdk15on:${bouncyCastleVersion}" + implementation "org.web3j:core:${web3jVersion}" implementation "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" implementation "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" implementation "com.fasterxml.jackson.core:jackson-annotations:${jacksonVersion}" diff --git a/gradle.properties b/gradle.properties index ffe888527..713102dfa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,15 +1,17 @@ -sbs4jVersion=0.1.8 +bouncyCastleVersion=1.69 commonsIoVersion=2.11.0 cryptokeyVersion=0.4.0 cxfRtRsSseVersion=3.5.5 -lombokPluginVersion=6.2.0 -jupiterVersion=5.9.0 -jsonrpc4jVersion=1.6.1-oak jacksonVersion=2.13.4 +javaTuplesVersion=1.2 +jodaTimeVersion=2.11.1 jsonassertVersion=1.5.1 jsonPathAssertVersion=2.7.0 +jsonrpc4jVersion=1.6.1-oak +jupiterVersion=5.9.0 mockwebserverVersion=4.10.0 log4jVersion=2.18.0 +lombokPluginVersion=6.2.0 +sbs4jVersion=0.1.8 slf4jApiVersion=2.0.0 -javaTuplesVersion=1.2 -jodaTimeVersion=2.11.1 +web3jVersion=5.0.0 From 8e15ee48a9dd1680d4f7a02af70a53d71c6e7ee1 Mon Sep 17 00:00:00 2001 From: meywood <105049338+meywood@users.noreply.github.com> Date: Mon, 15 Apr 2024 14:47:22 +0200 Subject: [PATCH 5/7] issues/263 - bump version to 2.5.4 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6de857105..04d55e661 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ apply plugin: 'java' group = 'network.casper' // Version number update for release -version='2.5.3' +version='2.5.4' sourceCompatibility = 1.8 targetCompatibility = 1.8 From daa747a26e4e45255a28f5c068961f4dab7b0752 Mon Sep 17 00:00:00 2001 From: meywood <105049338+meywood@users.noreply.github.com> Date: Mon, 15 Apr 2024 17:05:52 +0200 Subject: [PATCH 6/7] issues/263 - Tidy up for review --- src/main/java/com/syntifi/crypto/key/ASN1Identifiers.java | 4 ++-- src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java | 1 - src/main/java/com/syntifi/crypto/key/encdec/Base58.java | 2 +- .../java/com/syntifi/crypto/key/mnemonic/MnemonicCode.java | 1 - .../crypto/key/mnemonic/exception/MnemonicException.java | 2 +- .../syntifi/crypto/key/checksum/MixedCaseChecksumTest.java | 1 - .../key/deterministic/HierarchicalDeterministicKeyTest.java | 1 - src/test/java/com/syntifi/crypto/key/encdec/Base58Test.java | 2 +- 8 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/syntifi/crypto/key/ASN1Identifiers.java b/src/main/java/com/syntifi/crypto/key/ASN1Identifiers.java index 0753d149e..e28db82b6 100644 --- a/src/main/java/com/syntifi/crypto/key/ASN1Identifiers.java +++ b/src/main/java/com/syntifi/crypto/key/ASN1Identifiers.java @@ -12,7 +12,7 @@ * @since 0.1.0 */ @NoArgsConstructor(access = AccessLevel.PRIVATE) -public class ASN1Identifiers{ +public class ASN1Identifiers { public static final ASN1ObjectIdentifier Secp256k1OIDCurve = new ASN1ObjectIdentifier("1.3.132.0.10"); public static final ASN1ObjectIdentifier Secp256k1OIDkey = new ASN1ObjectIdentifier("1.2.840.10045.2.1"); @@ -22,4 +22,4 @@ public class ASN1Identifiers{ public static final String PUBLIC_KEY_DER_HEADER = "PUBLIC KEY"; public static final String PRIVATE_KEY_DER_HEADER = "PRIVATE KEY"; public static final String EC_PRIVATE_KEY_DER_HEADER = "EC PRIVATE KEY"; -} \ No newline at end of file +} diff --git a/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java b/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java index 0f7318ae4..8a2283f5e 100644 --- a/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java +++ b/src/main/java/com/syntifi/crypto/key/Secp256k1PublicKey.java @@ -41,7 +41,6 @@ public void loadPublicKey(final byte[] publicKey) throws IOException { } else { throw new IOException(); } - } @Override diff --git a/src/main/java/com/syntifi/crypto/key/encdec/Base58.java b/src/main/java/com/syntifi/crypto/key/encdec/Base58.java index 0df7cb587..14df4ebfb 100644 --- a/src/main/java/com/syntifi/crypto/key/encdec/Base58.java +++ b/src/main/java/com/syntifi/crypto/key/encdec/Base58.java @@ -160,4 +160,4 @@ private static byte divmod(byte[] number, int firstDigit, int base, int divisor) } return (byte) remainder; } -} \ No newline at end of file +} diff --git a/src/main/java/com/syntifi/crypto/key/mnemonic/MnemonicCode.java b/src/main/java/com/syntifi/crypto/key/mnemonic/MnemonicCode.java index 48a28d50b..804e9550f 100644 --- a/src/main/java/com/syntifi/crypto/key/mnemonic/MnemonicCode.java +++ b/src/main/java/com/syntifi/crypto/key/mnemonic/MnemonicCode.java @@ -140,7 +140,6 @@ private boolean[] bytesToBits(byte[] data) { return bits; } - /** * Gets the word list this code uses. * diff --git a/src/main/java/com/syntifi/crypto/key/mnemonic/exception/MnemonicException.java b/src/main/java/com/syntifi/crypto/key/mnemonic/exception/MnemonicException.java index 0a969cf58..0474d64c3 100644 --- a/src/main/java/com/syntifi/crypto/key/mnemonic/exception/MnemonicException.java +++ b/src/main/java/com/syntifi/crypto/key/mnemonic/exception/MnemonicException.java @@ -62,4 +62,4 @@ public MnemonicWordException(String badWord) { this.badWord = badWord; } } -} \ No newline at end of file +} diff --git a/src/test/java/com/syntifi/crypto/key/checksum/MixedCaseChecksumTest.java b/src/test/java/com/syntifi/crypto/key/checksum/MixedCaseChecksumTest.java index 0a8b06871..814cd9c14 100644 --- a/src/test/java/com/syntifi/crypto/key/checksum/MixedCaseChecksumTest.java +++ b/src/test/java/com/syntifi/crypto/key/checksum/MixedCaseChecksumTest.java @@ -34,5 +34,4 @@ void cep57houldMatchUpperCaseAddress() { assertEquals("51DA5aE5C39880Bfe4f94B0898332d1BD37e647F72f79Cf23475df1Bb1f85bEA", MixedCaseChecksum.checksumEncodeCEP57("51da5ae5c39880bfe4f94b0898332d1bd37e647f72f79cf23475df1bb1f85bea")); } - } diff --git a/src/test/java/com/syntifi/crypto/key/deterministic/HierarchicalDeterministicKeyTest.java b/src/test/java/com/syntifi/crypto/key/deterministic/HierarchicalDeterministicKeyTest.java index 7cac1b814..ab54b2809 100644 --- a/src/test/java/com/syntifi/crypto/key/deterministic/HierarchicalDeterministicKeyTest.java +++ b/src/test/java/com/syntifi/crypto/key/deterministic/HierarchicalDeterministicKeyTest.java @@ -17,7 +17,6 @@ public class HierarchicalDeterministicKeyTest { private static final Logger LOGGER = LoggerFactory.getLogger(HierarchicalDeterministicKey.class); - @Test void getMasterKeyFromSeed_seed_should_match() { byte[] init = "ed25519 seed".getBytes(StandardCharsets.UTF_8); diff --git a/src/test/java/com/syntifi/crypto/key/encdec/Base58Test.java b/src/test/java/com/syntifi/crypto/key/encdec/Base58Test.java index 2da2e67b6..4c386b149 100644 --- a/src/test/java/com/syntifi/crypto/key/encdec/Base58Test.java +++ b/src/test/java/com/syntifi/crypto/key/encdec/Base58Test.java @@ -19,4 +19,4 @@ void bs58() { assertEquals(expected, Base58.encode(bytes)); assertArrayEquals(Base58.decode(expected), bytes); } -} \ No newline at end of file +} From 8d58c1c002264b0e1808b91944b5b0b9ae45f7ed Mon Sep 17 00:00:00 2001 From: meywood <105049338+meywood@users.noreply.github.com> Date: Mon, 15 Apr 2024 17:18:32 +0200 Subject: [PATCH 7/7] issues/263 - Changed to obtain TypeFactory from the DeserializationContext. --- .../AbstractAnyOfDeserializer.java | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/casper/sdk/jackson/deserializer/AbstractAnyOfDeserializer.java b/src/main/java/com/casper/sdk/jackson/deserializer/AbstractAnyOfDeserializer.java index 07643f629..e989f30f1 100644 --- a/src/main/java/com/casper/sdk/jackson/deserializer/AbstractAnyOfDeserializer.java +++ b/src/main/java/com/casper/sdk/jackson/deserializer/AbstractAnyOfDeserializer.java @@ -1,36 +1,31 @@ package com.casper.sdk.jackson.deserializer; -import java.io.IOException; - import com.casper.sdk.exception.NoSuchTypeException; +import com.casper.sdk.jackson.resolver.CLValueResolver; +import com.casper.sdk.model.clvalue.AbstractCLValue; import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.BeanProperty; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.jsontype.TypeIdResolver; import com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer; import com.fasterxml.jackson.databind.node.TreeTraversingParser; import com.fasterxml.jackson.databind.type.TypeFactory; -import com.casper.sdk.jackson.resolver.CLValueResolver; -import com.casper.sdk.model.clvalue.AbstractCLValue; + +import java.io.IOException; /** * Core Deserializer for the CLValue property. This deserializer is used by the * {@link CLValueResolver} to return the correct CLType object in Java depending * on the cl_type sent over json - * + * * @author Alexandre Carvalho * @author Andre Bertolace - * @since 0.0.1 * @see AbstractCLValue + * @since 0.0.1 */ public abstract class AbstractAnyOfDeserializer extends AsPropertyTypeDeserializer { protected AbstractAnyOfDeserializer(final JavaType bt, final TypeIdResolver idRes, final String typePropertyName, - final boolean typeIdVisible, JavaType defaultImpl) { + final boolean typeIdVisible, JavaType defaultImpl) { super(bt, idRes, typePropertyName, typeIdVisible, defaultImpl); } @@ -50,7 +45,7 @@ public Object deserializeTypedFromObject(final JsonParser jp, final Deserializat } catch (NoSuchTypeException e) { throw new IOException("Parse error", e); } - TypeFactory factory = new ObjectMapper().getTypeFactory(); + TypeFactory factory = ctxt.getTypeFactory(); JavaType type = factory.constructType(subType); try (JsonParser jsonParser = new TreeTraversingParser(node, jp.getCodec())) { @@ -64,9 +59,9 @@ public Object deserializeTypedFromObject(final JsonParser jp, final Deserializat /** * Returns the node which contains the type key. - * + *

* Override if you have a child node which holds the type information. - * + * * @param currentNode the current deserialization node * @return node which contains the type key. */ @@ -76,7 +71,7 @@ protected JsonNode getTypeNode(JsonNode currentNode) { /** * Method that returns the instance of the found type - * + * * @param classType the name of the class type * @return {@link Class} of the type * @throws NoSuchTypeException thrown if no type for the given classType String