diff --git a/xyz.balzaclang.balzac.cli/.classpath b/xyz.balzaclang.balzac.cli/.classpath
index 002ad570..5e8a55fe 100644
--- a/xyz.balzaclang.balzac.cli/.classpath
+++ b/xyz.balzaclang.balzac.cli/.classpath
@@ -6,11 +6,6 @@
-
-
-
-
-
@@ -18,12 +13,6 @@
-
-
-
-
-
-
diff --git a/xyz.balzaclang.balzac.examples/src/main/java/bug.balzac b/xyz.balzaclang.balzac.examples/src/main/java/bug.balzac
index 6b6d8729..79ad2677 100644
--- a/xyz.balzaclang.balzac.examples/src/main/java/bug.balzac
+++ b/xyz.balzaclang.balzac.examples/src/main/java/bug.balzac
@@ -16,7 +16,7 @@ const kC = key:cVhDA3Yxkeacnci8WUokAfQT6Nv4tGpmy1GzSYtJdYqDDwZipPPB
const kCpub = kB.toPubkey
// tx redeemable with Alice's private key
-transaction A_funds {
+transaction A_funds {
input = _
output = 1 BTC: fun(x). versig(kApub; x)
}
diff --git a/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/ECKeyStore.java b/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/PrivateKeysStore.java
similarity index 89%
rename from xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/ECKeyStore.java
rename to xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/PrivateKeysStore.java
index 0847a467..b10e5d6f 100644
--- a/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/ECKeyStore.java
+++ b/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/PrivateKeysStore.java
@@ -46,7 +46,7 @@
import xyz.balzaclang.lib.model.PrivateKey;
import xyz.balzaclang.lib.utils.BitcoinUtils;
-public class ECKeyStore {
+public class PrivateKeysStore {
public static String getUniqueID(PrivateKey key) {
return BitcoinUtils.encode(Utils.sha256hash160(key.getBytes()));
@@ -55,15 +55,16 @@ public static String getUniqueID(PrivateKey key) {
private char[] password;
private KeyStore ks;
private Map netwotkTypeMap = new HashMap<>();
+ private Map compressPubkeyMap = new HashMap<>();
/**
* Create a new ECKeyStore with an empty password. Use
* {@link #changePassword(char[])} to set a new password.
- *
+ *
* @return an instance of ECKeyStore
* @throws KeyStoreException if an error occur creating the {@link KeyStore}
*/
- public ECKeyStore() throws KeyStoreException {
+ public PrivateKeysStore() throws KeyStoreException {
this(new char[0]);
}
@@ -71,24 +72,24 @@ public ECKeyStore() throws KeyStoreException {
* Create a new ECKeyStore with the specified password. The same password is
* used to store the keystore via {@link #store(File)} and for entries. Use
* {@link #changePassword(char[])} to set a new password.
- *
+ *
* @param password a password for the store and its entries.
* @return an instance of ECKeyStore.
* @throws KeyStoreException if an error occur creating the {@link KeyStore}
*/
- public ECKeyStore(char[] password) throws KeyStoreException {
+ public PrivateKeysStore(char[] password) throws KeyStoreException {
this(null, password);
}
/**
* Load the keystore from the given input stream, or create a new one if null.
* The password is used to decrypt the keystore and each entry.
- *
+ *
* @param input the input stream from which load the keystore.
* @param password a password for the store and its entries.
* @throws KeyStoreException
*/
- public ECKeyStore(InputStream input, char[] password) throws KeyStoreException {
+ public PrivateKeysStore(InputStream input, char[] password) throws KeyStoreException {
this.password = Arrays.copyOf(password, password.length);
this.ks = KeyStore.getInstance("pkcs12");
try {
@@ -104,6 +105,7 @@ public String addKey(PrivateKey key) throws KeyStoreException {
SecretKeyEntry kEntry = new SecretKeyEntry(secretKey);
ks.setEntry(keyID, kEntry, new PasswordProtection(password));
netwotkTypeMap.put(keyID, key.getNetworkType());
+ compressPubkeyMap.put(keyID, key.compressPublicKey());
return keyID;
}
@@ -112,7 +114,9 @@ public PrivateKey getKey(String keyID) throws KeyStoreException {
Key entryKey;
try {
entryKey = ks.getKey(keyID, password);
- return PrivateKey.from(entryKey.getEncoded(), netwotkTypeMap.get(keyID));
+ boolean compressPublicKey = compressPubkeyMap.get(keyID);
+ NetworkType networkType = netwotkTypeMap.get(keyID);
+ return PrivateKey.from(entryKey.getEncoded(), compressPublicKey, networkType);
} catch (UnrecoverableKeyException | NoSuchAlgorithmException e) {
throw new KeyStoreException("Cannot fetch key " + keyID + ": " + e.getMessage(), e);
}
diff --git a/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/PrivateKey.java b/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/PrivateKey.java
index 8783bb09..4210fb86 100644
--- a/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/PrivateKey.java
+++ b/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/PrivateKey.java
@@ -23,6 +23,8 @@ public interface PrivateKey {
public byte[] getBytes();
+ public boolean compressPublicKey();
+
public String getWif();
public String getBytesAsString();
@@ -33,21 +35,21 @@ public interface PrivateKey {
public NetworkType getNetworkType();
+ public PrivateKey withNetwork(NetworkType networkType);
+
public static PrivateKey fromBase58(String wif) {
DumpedPrivateKey key = DumpedPrivateKey.fromBase58(null, wif);
- return from(key.getKey().getPrivKeyBytes(), NetworkType.from(key.getParameters()));
+ byte[] keyBytes = key.getKey().getPrivKeyBytes();
+ boolean compressPubkey = key.isPubKeyCompressed();
+ return from(keyBytes, compressPubkey, NetworkType.from(key.getParameters()));
}
- public static PrivateKey from(byte[] keyBytes, NetworkType params) {
- return new PrivateKeyImpl(keyBytes, params);
+ public static PrivateKey from(byte[] keyBytes, boolean compressPubkey, NetworkType params) {
+ return new PrivateKeyImpl(keyBytes, compressPubkey, params);
}
public static PrivateKey fresh(NetworkType params) {
- return from(new ECKey().getPrivKeyBytes(), params);
+ ECKey key = new ECKey();
+ return from(key.getPrivKeyBytes(), key.isCompressed(), params);
}
-
- public static PrivateKey copy(PrivateKey key, NetworkType params) {
- return from(key.getBytes(), params);
- }
-
}
diff --git a/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/PrivateKeyImpl.java b/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/PrivateKeyImpl.java
index a5967378..5f456b1b 100644
--- a/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/PrivateKeyImpl.java
+++ b/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/PrivateKeyImpl.java
@@ -26,13 +26,15 @@ class PrivateKeyImpl implements PrivateKey {
private final NetworkType params;
private final byte[] privkey;
+ private final boolean compressPubkey;
private final PublicKey pubkey;
private final Address address;
- PrivateKeyImpl(byte[] privkey, NetworkType params) {
+ PrivateKeyImpl(byte[] privkey, boolean compressPubkey, NetworkType params) {
this.params = params;
this.privkey = Arrays.copyOf(privkey, privkey.length);
- this.pubkey = PublicKey.fromBytes(ECKey.fromPrivate(privkey).getPubKey());
+ this.compressPubkey = compressPubkey;
+ this.pubkey = PublicKey.fromBytes(ECKey.fromPrivate(privkey, compressPubkey).getPubKey());
this.address = Address.fromPubkey(pubkey.getBytes(), params);
}
@@ -41,9 +43,15 @@ public byte[] getBytes() {
return Arrays.copyOf(privkey, privkey.length);
}
+
+ @Override
+ public boolean compressPublicKey() {
+ return compressPubkey;
+ }
+
@Override
public String getWif() {
- return ECKey.fromPrivate(privkey).getPrivateKeyAsWiF(params.toNetworkParameters());
+ return ECKey.fromPrivate(privkey, compressPubkey).getPrivateKeyAsWiF(params.toNetworkParameters());
}
@Override
@@ -66,6 +74,11 @@ public NetworkType getNetworkType() {
return params;
}
+ @Override
+ public PrivateKey withNetwork(NetworkType networkType) {
+ return new PrivateKeyImpl(privkey, compressPubkey, networkType);
+ }
+
@Override
public int hashCode() {
final int prime = 31;
diff --git a/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/Signature.java b/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/Signature.java
index dbf35e00..bbfbd9dc 100644
--- a/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/Signature.java
+++ b/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/Signature.java
@@ -27,7 +27,7 @@
import org.bitcoinj.core.VerificationException;
import org.bitcoinj.crypto.TransactionSignature;
-import xyz.balzaclang.lib.ECKeyStore;
+import xyz.balzaclang.lib.PrivateKeysStore;
import xyz.balzaclang.lib.model.transaction.ITransactionBuilder;
import xyz.balzaclang.lib.model.transaction.Input;
import xyz.balzaclang.lib.model.transaction.Output;
@@ -96,7 +96,7 @@ public boolean equals(Object obj) {
public static Signature computeSignature(
PrivateKey key,
ITransactionBuilder txBuilder,
- ECKeyStore keyStore,
+ PrivateKeysStore keyStore,
int inputIndex,
SignatureModifier modifier) {
diff --git a/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/script/AbstractScriptBuilder.java b/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/script/AbstractScriptBuilder.java
index 695284bd..36f11d58 100644
--- a/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/script/AbstractScriptBuilder.java
+++ b/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/script/AbstractScriptBuilder.java
@@ -34,7 +34,7 @@
*
* Examples:
*
- *
+ *
*
* // OK
* new AbstractScriptBuilder(){}.number(42).number(5).data(new byte[]{})
@@ -128,22 +128,22 @@ public Script build() {
*
*
*
- *
+ *
*
* ... 42 (TOALTSTACK FROMALTSTACK)* 21 ...
*
- *
+ *
*
*
- *
+ *
*
* ... 42 21 ...
*
- *
+ *
*
*
*
- *
+ *
* @return this builder
*/
@SuppressWarnings("unchecked")
@@ -157,7 +157,7 @@ public T optimize() {
/**
* Optimize the given script, returning a copy. A copy is returned even if no
* optimization can be performed.
- *
+ *
* @param script the script to optimize.
* @return an optimized script.
*/
diff --git a/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/script/AbstractScriptBuilderWithVar.java b/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/script/AbstractScriptBuilderWithVar.java
index 5e2711b6..c9d24c1e 100644
--- a/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/script/AbstractScriptBuilderWithVar.java
+++ b/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/script/AbstractScriptBuilderWithVar.java
@@ -49,7 +49,7 @@
import org.bitcoinj.script.ScriptChunk;
import org.bitcoinj.script.ScriptOpCodes;
-import xyz.balzaclang.lib.ECKeyStore;
+import xyz.balzaclang.lib.PrivateKeysStore;
import xyz.balzaclang.lib.model.Hash;
import xyz.balzaclang.lib.model.PrivateKey;
import xyz.balzaclang.lib.model.Signature;
@@ -221,7 +221,7 @@ private Script substituteAllBinding() {
/**
* Replace all the signatures placeholder with the actual signatures. Each
* placeholder is already associated with the key and the modifiers.
- *
+ *
* @param tx the transaction to be signed
* @param inputIndex the index of the input that will contain this script
* @param outScript the redeemed output script
@@ -229,7 +229,7 @@ private Script substituteAllBinding() {
* @throws KeyStoreException if an error occurs retrieving private keys
*/
@SuppressWarnings("unchecked")
- public T setAllSignatures(ECKeyStore keystore, Transaction tx, int inputIndex, byte[] outScript, boolean isP2PKH)
+ public T setAllSignatures(PrivateKeysStore keystore, Transaction tx, int inputIndex, byte[] outScript, boolean isP2PKH)
throws KeyStoreException {
List newChunks = new ArrayList<>();
@@ -284,7 +284,7 @@ public T setAllSignatures(ECKeyStore keystore, Transaction tx, int inputIndex, b
/**
* Append the given script to this builder.
- *
+ *
* @param append the script to append
* @return this builder
*/
@@ -296,7 +296,7 @@ public T append(Script append) {
/**
* Append the given script builder to this one. If it contains some free
* variables or signatures placeholder, they are merged ensuring consistency.
- *
+ *
* @param the concrete type of the given builder
* @param append the script builder to append
* @return this builder
@@ -352,7 +352,7 @@ else if (isSignature(ch)) {
/**
* Extract a string representation of this builder.
- *
+ *
* @return a string representing this builder
*/
public String serialize() {
@@ -365,7 +365,7 @@ public String serialize() {
/**
* Parse the given string to initialize this builder.
- *
+ *
* @param str a string representation of this builder
* @return this builder
*/
diff --git a/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/transaction/ITransactionBuilder.java b/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/transaction/ITransactionBuilder.java
index d0ab0e45..95cda404 100644
--- a/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/transaction/ITransactionBuilder.java
+++ b/xyz.balzaclang.balzac.lib/src/main/java/xyz/balzaclang/lib/model/transaction/ITransactionBuilder.java
@@ -24,7 +24,7 @@
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Utils;
-import xyz.balzaclang.lib.ECKeyStore;
+import xyz.balzaclang.lib.PrivateKeysStore;
import xyz.balzaclang.lib.model.NetworkType;
import xyz.balzaclang.lib.utils.EnvI;
@@ -33,7 +33,7 @@ public interface ITransactionBuilder extends EnvI