Memo Object
This commit is contained in:
parent
b35ef3a1f1
commit
c6261fc479
6 changed files with 195 additions and 78 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.*;
|
||||
|
@ -50,7 +53,6 @@ public class Test {
|
|||
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) {
|
||||
|
@ -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())
|
||||
|
@ -700,4 +702,16 @@ public class Test {
|
|||
}
|
||||
}
|
||||
|
||||
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()));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue