Memo Object

This commit is contained in:
Henry Varona 2016-12-10 16:32:57 -04:00
parent b35ef3a1f1
commit c6261fc479
6 changed files with 195 additions and 78 deletions

View file

@ -50,7 +50,7 @@ public class Main {
// test.testGetDynamicParams();
// test.testGetRequiredFeesSerialization();
// test.testRequiredFeesResponse();
test.testTransactionBroadcastSequence();
// test.testTransactionBroadcastSequence();
// test.testAccountLookupDeserialization();
// test.testPrivateKeyManipulations();
// test.testPublicKeyManipulations();
@ -69,5 +69,6 @@ public class Main {
// test.testCreateBinFile();
// test.testImportBinFile();
//test.testLookupAccounts();
test.testDecodeMemo();
}
}

View file

@ -1,14 +1,17 @@
package com.luminiasoft.bitshares;
import com.luminiasoft.bitshares.objects.Memo;
import com.google.common.primitives.UnsignedLong;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
import com.luminiasoft.bitshares.errors.MalformedAddressException;
import com.luminiasoft.bitshares.errors.MalformedTransactionException;
import com.luminiasoft.bitshares.interfaces.WitnessResponseListener;
import com.luminiasoft.bitshares.models.*;
import com.luminiasoft.bitshares.objects.MemoBuilder;
import com.luminiasoft.bitshares.test.NaiveSSLContext;
import com.luminiasoft.bitshares.ws.*;
import com.neovisionaries.ws.client.*;
@ -49,8 +52,7 @@ public class Test {
System.out.println("Got account properties");
System.out.println("account: " + accountProperties.toString());
System.out.println("id: " + accountProperties.id);
} else if (response.result.getClass() == ArrayList.class) {
List list = (List) response.result;
if (list.size() > 0) {
@ -99,7 +101,7 @@ public class Test {
System.out.println("Got empty list!");
}
} else if (response.result.getClass() == JsonArray.class) {
System.out.println("Json array : " + ((JsonArray)response.result));
System.out.println("Json array : " + ((JsonArray) response.result));
} else {
System.out.println("Got other: " + response.result.getClass());
}
@ -294,14 +296,14 @@ public class Test {
try {
// Creating memo
PublicKey from = new PublicKey(ECKey.fromPublicOnly(new BrainKey(Main.BILTHON_83_BRAIN_KEY, 0).getPublicKey()));
PublicKey from = new PublicKey(new BrainKey(Main.BILTHON_83_BRAIN_KEY, 0).getPrivateKey());
PublicKey to = new PublicKey(ECKey.fromPublicOnly(new BrainKey(Main.BILTHON_5_BRAIN_KEY, 0).getPublicKey()));
Memo memo = new Memo(from, to, "sample message");
Memo memo = new MemoBuilder().setFromKey(from).setToKey(to).setMessage("sample message").build();
// Creating transaction
Transaction transaction = new TransferTransactionBuilder()
.setSource(new UserAccount("1.2.138632")) // bilthon-83
.setDestination(new UserAccount("1.2.139313")) // bilthon-5
.setSource(new UserAccount("1.2.139270")) // bilthon-83
.setDestination(new UserAccount("1.2.142115")) // bilthon-5
.setAmount(new AssetAmount(UnsignedLong.valueOf(1), new Asset("1.3.0")))
.setFee(new AssetAmount(UnsignedLong.valueOf(264174), new Asset("1.3.0")))
.setPrivateKey(new BrainKey(Main.BILTHON_83_BRAIN_KEY, 0).getPrivateKey())
@ -357,7 +359,7 @@ public class Test {
System.out.println("base58...................: " + Base58.encode(privateKey.getPubKey()));
}
public void testPublicKeyManipulations(){
public void testPublicKeyManipulations() {
// PublicKey publicKey = new PublicKey("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY");
// System.out.println("Public key bytes");
// System.out.println(Util.bytesToHex(publicKey.toBytes()));
@ -427,17 +429,17 @@ public class Test {
String suggestion = BrainKey.suggest(words);
brainKey = new BrainKey(suggestion, 0);
} else {
System.out.println("Using brain key: "+Main.BILTHON_5_BRAIN_KEY);
System.out.println("Using brain key: " + Main.BILTHON_5_BRAIN_KEY);
// brainKey = new BrainKey(Main.BILTHON_83_BRAIN_KEY, 0);
brainKey = new BrainKey("CYNEBOT LUFBERY DAUNTER TOO SALOOP HOPOFF DIAULOS REV AES TORPOR RECTRIX DEVILRY", 0);
}
ECKey key = brainKey.getPrivateKey();
System.out.println("Private key..................: "+Util.bytesToHex(key.getSecretBytes()));
System.out.println("Private key..................: " + Util.bytesToHex(key.getSecretBytes()));
String wif = key.getPrivateKeyAsWiF(NetworkParameters.fromID(NetworkParameters.ID_MAINNET));
System.out.println("Wif Compressed...............: " + wif);
String wif2 = key.decompress().getPrivateKeyAsWiF(NetworkParameters.fromID(NetworkParameters.ID_MAINNET));
System.out.println("Wif Decompressed.............: " + wif2);
System.out.println("Wif from BrainKey............: "+ brainKey.getWalletImportFormat());
System.out.println("Wif from BrainKey............: " + brainKey.getWalletImportFormat());
byte[] uncompressedPubKey = key.decompress().getPubKey();
byte[] compressedPubKey = key.getPubKey();
@ -604,14 +606,14 @@ public class Test {
System.out.println(transaction.toJsonString());
System.out.println("Serialized transaction");
System.out.println(Util.bytesToHex(transaction.toBytes()));
} catch(MalformedAddressException e){
System.out.println("MalformedAddressException. Msg: "+e.getMessage());
} catch (MalformedAddressException e) {
System.out.println("MalformedAddressException. Msg: " + e.getMessage());
} catch (MalformedTransactionException e) {
System.out.println("MalformedTransactionException. Msg: "+e.getMessage());
System.out.println("MalformedTransactionException. Msg: " + e.getMessage());
}
}
public void testAccountUpdateOperationBroadcast(){
public void testAccountUpdateOperationBroadcast() {
WitnessResponseListener listener = new WitnessResponseListener() {
@Override
@ -653,19 +655,19 @@ public class Test {
mWebSocket.connect();
} catch (MalformedAddressException e) {
System.out.println("MalformedAddressException. Msg: "+e.getMessage());
System.out.println("MalformedAddressException. Msg: " + e.getMessage());
} catch (MalformedTransactionException e) {
System.out.println("MalformedTransactionException. Msg: "+e.getMessage());
System.out.println("MalformedTransactionException. Msg: " + e.getMessage());
} catch (NoSuchAlgorithmException e) {
System.out.println("NoSuchAlgorithmException. Msg: "+e.getMessage());
System.out.println("NoSuchAlgorithmException. Msg: " + e.getMessage());
} catch (IOException e) {
System.out.println("IOException. Msg: "+e.getMessage());
System.out.println("IOException. Msg: " + e.getMessage());
} catch (WebSocketException e) {
System.out.println("WebSocketException. Msg: "+e.getMessage());
System.out.println("WebSocketException. Msg: " + e.getMessage());
}
}
public void testLookupAccounts(){
public void testLookupAccounts() {
WitnessResponseListener listener = new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
@ -692,12 +694,24 @@ public class Test {
mWebSocket.connect();
} catch (NoSuchAlgorithmException e) {
System.out.println("NoSuchAlgorithmException. Msg: "+e.getMessage());
System.out.println("NoSuchAlgorithmException. Msg: " + e.getMessage());
} catch (WebSocketException e) {
System.out.println("WebSocketException. Msg: "+e.getMessage());
System.out.println("WebSocketException. Msg: " + e.getMessage());
} catch (IOException e) {
System.out.println("IOException. Msg: "+e.getMessage());
System.out.println("IOException. Msg: " + e.getMessage());
}
}
public void testDecodeMemo() {
PublicKey from = new PublicKey((new BrainKey(Main.BILTHON_83_BRAIN_KEY, 0).getPrivateKey()));
PublicKey to = new PublicKey(new BrainKey(Main.BILTHON_5_BRAIN_KEY, 0).getPrivateKey());
Memo sendMemo = new MemoBuilder().setFromKey(from).setToKey(to).setMessage("test message").build();
JsonElement memoJson = sendMemo.toJsonObject();
System.out.println("generated Json : " + memoJson.toString());
System.out.println("Decode Memo : " + Memo.decodeMessage(from, to, memoJson.getAsJsonObject().get("message").getAsString(), memoJson.getAsJsonObject().get("nonce").getAsString()));
}
}

View file

@ -1,5 +1,6 @@
package com.luminiasoft.bitshares;
import com.luminiasoft.bitshares.objects.Memo;
import com.google.common.primitives.Bytes;
import com.google.gson.*;
@ -65,6 +66,7 @@ public class TransferOperation extends BaseOperation {
@Override
public byte[] toBytes() {
System.out.println("ne toBytes");
byte[] feeBytes = fee.toBytes();
byte[] fromBytes = from.toBytes();
byte[] toBytes = to.toBytes();

View file

@ -1,5 +1,6 @@
package com.luminiasoft.bitshares;
import com.luminiasoft.bitshares.objects.Memo;
import com.luminiasoft.bitshares.errors.MalformedTransactionException;
import org.bitcoinj.core.ECKey;

View file

@ -1,8 +1,10 @@
package com.luminiasoft.bitshares;
package com.luminiasoft.bitshares.objects;
import com.google.common.primitives.Bytes;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.luminiasoft.bitshares.PublicKey;
import com.luminiasoft.bitshares.Util;
import com.luminiasoft.bitshares.crypto.SecureRandomStrengthener;
import com.luminiasoft.bitshares.interfaces.ByteSerializable;
import com.luminiasoft.bitshares.interfaces.JsonSerializable;
@ -10,8 +12,6 @@ import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import org.bitcoinj.core.Base58;
import org.bitcoinj.core.ECKey;
/**
* Created by nelson on 11/9/16.
@ -25,47 +25,25 @@ public class Memo implements ByteSerializable, JsonSerializable {
private PublicKey from;
private PublicKey to;
private byte[] nonce = new byte[8];
private final byte[] nonce = new byte[8];
private byte[] message;
/**
* Empty Constructor
*/
public Memo() {
this.from = null;
this.to = null;
this.nonce = null;
this.message = null;
}
public Memo(PublicKey from, PublicKey to, String message) {
this.from = from;
this.to = to;
this.message = message.getBytes();
this.encodeMessage(from.getKey(), to.getKey(), this.message, 0);
}
/**
* Constructor for receiving Message
*
* @param from Public Key of the source
* @param to Our Public Key
* @param message The message cnoded
* @param nonce The nonce used for encoding the message
* Implement metod, serialized this Object
* @return the byte array of this object serialized
*/
public Memo(PublicKey from, PublicKey to, String message, String nonce) {
this.from = from;
this.to = to;
this.message = new BigInteger(message, 16).toByteArray();
byte[] firstNonce = new BigInteger(nonce,10).toByteArray();
this.nonce = new byte[8];
System.arraycopy(firstNonce, firstNonce.length-8, this.nonce, 0, this.nonce.length);
//this.nonce = new BigInteger(nonce,10).toByteArray();
}
@Override
public byte[] toBytes() {
if ((this.from == null) || (this.to == null) || (this.nonce == null) || (this.message == null)) {
if ((this.from == null) || (this.to == null) || (this.message == null)) {
return new byte[]{(byte) 0};
} else {
byte[] nonceformat = new byte[nonce.length];
@ -76,40 +54,57 @@ public class Memo implements ByteSerializable, JsonSerializable {
}
}
public void encodeMessage(ECKey fromKey, ECKey toKey, byte[] msg) {
this.encodeMessage(fromKey, toKey, msg, 0);
/**
* Encode a memo message using the input source key and destination key
* @param fromKey The source destination, need to have a private key accesss
* @param toKey The destination, needs only the public key access
* @param msg The message in bytes
* @return a Memo corresponding with the message encoding
*/
public static Memo encodeMessage(PublicKey fromKey, PublicKey toKey, byte[] msg) {
return encodeMessage(fromKey, toKey, msg, 0);
}
public void encodeMessage(ECKey fromKey, ECKey toKey, byte[] msg, long custom_nonce) {
/**
* Encode a message a return a memo with that message encoded
*
* @param fromKey The source destination, need to have a private key accesss
* @param toKey The destination, needs only the public key access
* @param msg The message in bytes
* @param custom_nonce the custom nonce to be use or 0 to create a new one
* @return a Memo corresponding with the message encoding
*/
public static Memo encodeMessage(PublicKey fromKey, PublicKey toKey, byte[] msg, long custom_nonce) {
Memo memo = new Memo();
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
this.from = new PublicKey(fromKey);
this.to = new PublicKey(toKey);
memo.from = fromKey;
memo.to = toKey;
if (custom_nonce == 0) {
SecureRandomStrengthener randomStrengthener = SecureRandomStrengthener.getInstance();
//randomStrengthener.addEntropySource(new AndroidRandomSource());
SecureRandom secureRandom = randomStrengthener.generateAndSeedRandomNumberGenerator();
secureRandom.nextBytes(nonce);
secureRandom.nextBytes(memo.nonce);
long time = System.currentTimeMillis();
for (int i = 7; i >= 1; i--) {
this.nonce[i] = (byte) (time & 0xff);
memo.nonce[i] = (byte) (time & 0xff);
time = time / 0x100;
}
} else {
for (int i = 7; i >= 0; i--) {
this.nonce[i] = (byte) (custom_nonce & 0xff);
memo.nonce[i] = (byte) (custom_nonce & 0xff);
custom_nonce = custom_nonce / 0x100;
}
}
byte[] secret = toKey.getPubKeyPoint().multiply(fromKey.getPrivKey()).normalize().getXCoord().getEncoded();
byte[] finalKey = new byte[secret.length + this.nonce.length];
byte[] secret = toKey.getKey().getPubKeyPoint().multiply(fromKey.getKey().getPrivKey()).normalize().getXCoord().getEncoded();
byte[] finalKey = new byte[secret.length + memo.nonce.length];
System.arraycopy(secret, 0, finalKey, 0, secret.length);
System.arraycopy(this.nonce, 0, finalKey, secret.length, this.nonce.length);
System.arraycopy(memo.nonce, 0, finalKey, secret.length, memo.nonce.length);
byte[] sha256Msg = md.digest(msg);
byte[] serialChecksum = new byte[4];
@ -117,27 +112,57 @@ public class Memo implements ByteSerializable, JsonSerializable {
byte[] msgFinal = new byte[serialChecksum.length + msg.length];
System.arraycopy(serialChecksum, 0, msgFinal, 0, serialChecksum.length);
System.arraycopy(msg, 0, msgFinal, serialChecksum.length, msg.length);
this.message = Util.encryptAES(msgFinal, finalKey);
memo.message = Util.encryptAES(msgFinal, finalKey);
} catch (NoSuchAlgorithmException ex) {
}
return memo;
}
public String decodeMessage() {
/**
* returns the string coreesponding a encode memo
*
* @param fromKey The soruce key, need to have public key only
* @param toKey The destination key, need to have private key access
* @param msg The message to be decoded
* @param nonce The nonce used in the decoded message
* @return The message
*/
public static String decodeMessage(PublicKey fromKey, PublicKey toKey, byte[] msg, byte[] nonce) {
byte[] secret = this.from.getKey().getPubKeyPoint().multiply(this.to.getKey().getPrivKey()).normalize().getXCoord().getEncoded();
byte[] finalKey = new byte[secret.length + this.nonce.length];
byte[] secret = fromKey.getKey().getPubKeyPoint().multiply(toKey.getKey().getPrivKey()).normalize().getXCoord().getEncoded();
byte[] finalKey = new byte[secret.length + nonce.length];
System.arraycopy(secret, 0, finalKey, 0, secret.length);
System.arraycopy(this.nonce, 0, finalKey, secret.length, this.nonce.length);
System.arraycopy(nonce, 0, finalKey, secret.length, nonce.length);
byte[] msgFinal = Util.decryptAES(this.message, finalKey);
byte[] msgFinal = Util.decryptAES(msg, finalKey);
byte[] decodedMsg = new byte[msgFinal.length - 4];
//TODO verify checksum for integrity
System.arraycopy(msgFinal, 4, decodedMsg, 0, decodedMsg.length);
return new String(decodedMsg);
}
/**
* returns the string coreesponding a encode memo
*
* @param fromKey The soruce key, need to have public key only
* @param toKey The destination key, need to have private key access
* @param message The message to be decoded
* @param nonce The nonce used in the decoded message
* @return The message
*/
public static String decodeMessage(PublicKey fromKey, PublicKey toKey, String message, String nonce) {
byte[] msg = new BigInteger(message, 16).toByteArray();
if (msg[0] == 0) {
byte[] temp = new byte[msg.length - 1];
System.arraycopy(msg, 1, temp, 0, temp.length);
msg = temp;
}
byte[] firstNonce = new BigInteger(nonce, 10).toByteArray();
byte[] nonceByte = new byte[8];
System.arraycopy(firstNonce, firstNonce.length - 8, nonceByte, 0, nonceByte.length);
return decodeMessage(fromKey, toKey, msg, nonceByte);
}
@Override
public String toJsonString() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.

View file

@ -0,0 +1,74 @@
package com.luminiasoft.bitshares.objects;
import com.luminiasoft.bitshares.PublicKey;
/**
* Class to build a Memo Object
* @author henry 10/12/2016
*/
public class MemoBuilder {
private PublicKey fromKey;
private PublicKey toKey;
private String message;
private long nonce = 0;
/**
* Empty Constructor
*/
public MemoBuilder() {
}
/**
* Set the key of the Source, needs to have a private Key access
* @param fromKey The Public Key of the sender
* @return The MemoBuilder
*/
public MemoBuilder setFromKey(PublicKey fromKey) {
this.fromKey = fromKey;
return this;
}
/**
* Set the key of the destination, only need the public key.
* @param toKey The Public Key of the receiver
* @return The MemoBuilder
*/
public MemoBuilder setToKey(PublicKey toKey) {
this.toKey = toKey;
return this;
}
/**
* Set the message to be send
* @param message The message as a String
* @return The MemoBuilder
*/
public MemoBuilder setMessage(String message) {
this.message = message;
return this;
}
/**
* (Optional) Sets a custom nonce
* @param nonce The custom nonce
* @return The MemoBuilder
*/
public MemoBuilder setNone(Long nonce) {
this.nonce = nonce;
return this;
}
/**
* Biulds the memo object
* @return The Memo object
*/
public Memo build() {
//Todo unencode key
if (nonce == 0) {
return Memo.encodeMessage(fromKey, toKey, message.getBytes());
}
return Memo.encodeMessage(fromKey, toKey, message.getBytes(), nonce);
}
}