diff --git a/core/src/main/java/org/bitcoinj/crypto/BLSAbstractLazyObject.java b/core/src/main/java/org/bitcoinj/crypto/BLSAbstractLazyObject.java index 158d30d24..bb6130268 100644 --- a/core/src/main/java/org/bitcoinj/crypto/BLSAbstractLazyObject.java +++ b/core/src/main/java/org/bitcoinj/crypto/BLSAbstractLazyObject.java @@ -19,8 +19,11 @@ import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.ProtocolException; +import java.io.IOException; +import java.io.OutputStream; -public class BLSAbstractLazyObject extends Message { + +public abstract class BLSAbstractLazyObject extends Message { byte [] buffer; boolean initialized; @@ -46,6 +49,11 @@ protected void parse() throws ProtocolException { initialized = false; } + abstract protected void bitcoinSerializeToStream(OutputStream stream, boolean legacy) throws IOException; + + public void bitcoinSerialize(OutputStream stream, boolean legacy) throws IOException { + bitcoinSerializeToStream(stream, legacy); + } public boolean isInitialized() { return initialized; diff --git a/core/src/main/java/org/bitcoinj/crypto/BLSLazyPublicKey.java b/core/src/main/java/org/bitcoinj/crypto/BLSLazyPublicKey.java index cc0309b53..1fb23924c 100644 --- a/core/src/main/java/org/bitcoinj/crypto/BLSLazyPublicKey.java +++ b/core/src/main/java/org/bitcoinj/crypto/BLSLazyPublicKey.java @@ -73,6 +73,7 @@ protected void parse() throws ProtocolException { length = cursor - offset; } + @Override protected void bitcoinSerializeToStream(OutputStream stream) throws IOException { if (!initialized && buffer == null) { @@ -85,7 +86,8 @@ protected void bitcoinSerializeToStream(OutputStream stream) throws IOException } } - public void bitcoinSerialize(OutputStream stream, boolean legacy) throws IOException { + @Override + protected void bitcoinSerializeToStream(OutputStream stream, boolean legacy) throws IOException { if (!initialized && buffer == null) { throw new IOException("public key and buffer are not initialized"); } @@ -147,4 +149,12 @@ public boolean equals(Object o) { public int hashCode() { return publicKey != null ? publicKey.hashCode() : 0; } + + public boolean isValid() { + if (initialized) { + return publicKey.isValid(); + } else { + return buffer != null; + } + } } diff --git a/core/src/main/java/org/bitcoinj/crypto/BLSLazySignature.java b/core/src/main/java/org/bitcoinj/crypto/BLSLazySignature.java index 607540df0..0901bfead 100644 --- a/core/src/main/java/org/bitcoinj/crypto/BLSLazySignature.java +++ b/core/src/main/java/org/bitcoinj/crypto/BLSLazySignature.java @@ -64,6 +64,22 @@ protected void bitcoinSerializeToStream(OutputStream stream) throws IOException } } + protected void bitcoinSerializeToStream(OutputStream stream, boolean legacy) throws IOException { + lock.lock(); + try { + if (!initialized && buffer == null) { + log.warn("signature and buffer are not initialized"); + buffer = invalidSignature.getBuffer(); + } + if (buffer == null) { + buffer = signature.getBuffer(BLSSignature.BLS_CURVE_SIG_SIZE, legacy); + } + stream.write(buffer); + } finally { + lock.unlock(); + } + } + public BLSLazySignature assign(BLSLazySignature blsLazySignature) { lock.lock(); try { @@ -121,4 +137,12 @@ public BLSSignature getSignature() { public String toString() { return initialized ? signature.toString() : (buffer == null ? invalidSignature.toString() : Utils.HEX.encode(buffer)); } + + public boolean isValid() { + if (initialized) { + return signature.isValid(); + } else { + return buffer != null; + } + } } diff --git a/core/src/main/java/org/bitcoinj/crypto/BLSSignature.java b/core/src/main/java/org/bitcoinj/crypto/BLSSignature.java index 53be4ee59..ff7dd9c08 100644 --- a/core/src/main/java/org/bitcoinj/crypto/BLSSignature.java +++ b/core/src/main/java/org/bitcoinj/crypto/BLSSignature.java @@ -255,7 +255,7 @@ public boolean recover(ArrayList sigs, ArrayList ids) public boolean checkMalleable(byte [] buf, int size) { - byte [] buf2 = getBuffer(serializedSize); + byte [] buf2 = getBuffer(serializedSize, legacy); if (!Arrays.equals(buf, buf2)) { // TODO not sure if this is actually possible with the BLS libs. I'm assuming here that somewhere deep inside // these libs masking might happen, so that 2 different binary representations could result in the same object diff --git a/core/src/main/java/org/bitcoinj/quorums/FinalCommitment.java b/core/src/main/java/org/bitcoinj/quorums/FinalCommitment.java index e6ffe808f..0690d5fd5 100644 --- a/core/src/main/java/org/bitcoinj/quorums/FinalCommitment.java +++ b/core/src/main/java/org/bitcoinj/quorums/FinalCommitment.java @@ -21,7 +21,6 @@ import org.bitcoinj.crypto.BLSLazyPublicKey; import org.bitcoinj.crypto.BLSLazySignature; import org.bitcoinj.crypto.BLSPublicKey; -import org.bitcoinj.crypto.BLSScheme; import org.bitcoinj.crypto.BLSSignature; import org.bitcoinj.evolution.Masternode; import org.bitcoinj.evolution.SpecialTxPayload; @@ -56,11 +55,11 @@ public class FinalCommitment extends SpecialTxPayload { ArrayList signers; ArrayList validMembers; - BLSPublicKey quorumPublicKey; + BLSLazyPublicKey quorumPublicKey; Sha256Hash quorumVvecHash; - BLSSignature quorumSignature; - BLSSignature membersSignature; + BLSLazySignature quorumSignature; + BLSLazySignature membersSignature; private boolean verified = false; public FinalCommitment(NetworkParameters params, byte [] payload, int offset) { @@ -90,10 +89,10 @@ public FinalCommitment(NetworkParameters params, int version, int quorumSize = LLMQParameters.fromType(LLMQParameters.LLMQType.fromValue(llmqType)).size; this.signers = Utils.booleanArrayList(quorumSize, signers); this.validMembers = Utils.booleanArrayList(quorumSize, validMembers); - this.quorumPublicKey = new BLSPublicKey(params, quorumPublicKey, 0, isLegacy()); + this.quorumPublicKey = new BLSLazyPublicKey(params, quorumPublicKey, 0, isLegacy()); this.quorumVvecHash = quorumVvecHash; - this.quorumSignature = signature.getSignature(); - this.membersSignature = membersSignature.getSignature(); + this.quorumSignature = new BLSLazySignature(signature); + this.membersSignature = new BLSLazySignature(membersSignature); length = 1 + 32 + (isIndexed() ? 2 : 0) + VarInt.sizeOf(quorumSize) * 2 + @@ -115,15 +114,15 @@ protected void parse() throws ProtocolException { signers = readBooleanArrayList(); validMembers = readBooleanArrayList(); - quorumPublicKey = new BLSPublicKey(params, payload, cursor, isLegacy()); + quorumPublicKey = new BLSLazyPublicKey(params, payload, cursor, isLegacy()); cursor += quorumPublicKey.getMessageSize(); quorumVvecHash = readHash(); - quorumSignature = new BLSSignature(params, payload, cursor, isLegacy()); + quorumSignature = new BLSLazySignature(params, payload, cursor, isLegacy()); cursor += quorumSignature.getMessageSize(); - membersSignature = new BLSSignature(params, payload, cursor, isLegacy()); + membersSignature = new BLSLazySignature(params, payload, cursor, isLegacy()); cursor += membersSignature.getMessageSize(); length = cursor - offset; @@ -293,7 +292,7 @@ public boolean verify(StoredBlock block, ArrayList members, boolean // sigs are only checked when the block is processed if (checkSigs) { - Sha256Hash commitmentHash = LLMQUtils.buildCommitmentHash(llmqParameters.type, quorumHash, validMembers, quorumPublicKey, quorumVvecHash); + Sha256Hash commitmentHash = LLMQUtils.buildCommitmentHash(llmqParameters.type, quorumHash, validMembers, quorumPublicKey.getPublicKey(), quorumVvecHash); ArrayList memberPubKeys = Lists.newArrayList(); for (int i = 0; i < members.size(); i++) { @@ -303,15 +302,15 @@ public boolean verify(StoredBlock block, ArrayList members, boolean memberPubKeys.add(members.get(i).getPubKeyOperator()); } - if (!membersSignature.verifySecureAggregated(memberPubKeys, commitmentHash, isLegacy())) { + if (!membersSignature.getSignature().verifySecureAggregated(memberPubKeys, commitmentHash, isLegacy())) { log.error("invalid aggregated members signature"); return false; } - Context.get().signingManager.logSignature("QUORUM", quorumPublicKey, commitmentHash, quorumSignature); + Context.get().signingManager.logSignature("QUORUM", quorumPublicKey.getPublicKey(), commitmentHash, quorumSignature.getSignature()); if(Context.get().masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.BLS_SIGNATURES)) { - if (!quorumSignature.verifyInsecure(quorumPublicKey, commitmentHash, isLegacy())) { + if (!quorumSignature.getSignature().verifyInsecure(quorumPublicKey.getPublicKey(), commitmentHash, isLegacy())) { log.error("invalid quorum signature"); return false; } @@ -393,7 +392,7 @@ public LLMQParameters.LLMQType getLlmqType() { } public BLSPublicKey getQuorumPublicKey() { - return quorumPublicKey; + return quorumPublicKey.getPublicKey(); } public Sha256Hash getQuorumVvecHash() { @@ -401,11 +400,11 @@ public Sha256Hash getQuorumVvecHash() { } public BLSSignature getMembersSignature() { - return membersSignature; + return membersSignature.getSignature(); } public BLSSignature getQuorumSignature() { - return quorumSignature; + return quorumSignature.getSignature(); } public ArrayList getSigners() { diff --git a/core/src/main/java/org/bitcoinj/quorums/Quorum.java b/core/src/main/java/org/bitcoinj/quorums/Quorum.java index 85f4e525d..c6b904324 100644 --- a/core/src/main/java/org/bitcoinj/quorums/Quorum.java +++ b/core/src/main/java/org/bitcoinj/quorums/Quorum.java @@ -2,6 +2,7 @@ import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.Sha256Hash; +import org.bitcoinj.crypto.BLSLazyPublicKey; import org.bitcoinj.crypto.BLSPublicKey; public class Quorum { @@ -22,7 +23,7 @@ public Quorum(LLMQParameters llmqParameters, FinalCommitment commitment) { public Quorum(NetworkParameters params, LLMQParameters llmqParameters, Sha256Hash quorumHash, BLSPublicKey publicKey) { this.llmqParameters = llmqParameters; this.commitment = new FinalCommitment(params, llmqParameters, quorumHash); - this.commitment.quorumPublicKey = publicKey; + this.commitment.quorumPublicKey = new BLSLazyPublicKey(publicKey); } @Override diff --git a/core/src/test/java/org/bitcoinj/quorums/FinalCommitmentTest.java b/core/src/test/java/org/bitcoinj/quorums/FinalCommitmentTest.java index 97b0538f4..34c7f8961 100644 --- a/core/src/test/java/org/bitcoinj/quorums/FinalCommitmentTest.java +++ b/core/src/test/java/org/bitcoinj/quorums/FinalCommitmentTest.java @@ -85,7 +85,7 @@ public void finalCommitmentTest() throws IOException { assertEquals(49, commitment.countValidMembers()); BLSPublicKey quorumPublickKey = new BLSPublicKey(PARAMS, Utils.HEX.decode("160b120058893acc8b6622dfd210f7d00aed97a43b364da4073b791c23b1e8b4b4c7943bf5b3b4c62c0108b391351a43"), 0, true); - assertEquals(quorumPublickKey, commitment.quorumPublicKey); + assertEquals(quorumPublickKey, commitment.quorumPublicKey.getPublicKey()); UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(txdata.length); assertArrayEquals(commitmentTx.getExtraPayload(), payload.getPayload()); @@ -152,7 +152,7 @@ public void finalCommitmentTestTwo() throws IOException { assertEquals(322, commitment.countValidMembers()); BLSPublicKey quorumPublickKey = new BLSPublicKey(PARAMS, Utils.HEX.decode("03a3fbbe99d80a9be8fc59fd4fe43dfbeba9119b688e97493664716cdf15ae47fad70fea7cb93f20fba10d689f9e3c02"), 0, true); - assertEquals(quorumPublickKey, commitment.quorumPublicKey); + assertEquals(quorumPublickKey, commitment.quorumPublicKey.getPublicKey()); assertArrayEquals(commitmentTx.getExtraPayload(), payload.getPayload()); // round trip @@ -184,7 +184,7 @@ public void finalCommitmentV2Test() throws IOException { assertEquals(10, commitment.countValidMembers()); BLSPublicKey quorumPublickKey = new BLSPublicKey(PARAMS, Utils.HEX.decode("0e22ac5b7c87076a03b1e4bee58c8404aaed183dd2c3114cea3ac1cbf85218a6196a19073789e9a12fc439b773842368"), 0, true); - assertEquals(quorumPublickKey, commitment.quorumPublicKey); + assertEquals(quorumPublickKey, commitment.quorumPublicKey.getPublicKey()); // round trip assertArrayEquals(qfcommit, commitment.bitcoinSerialize());