Skip to content

Commit

Permalink
fix: use Lazy BLS objects in FinalCommitment
Browse files Browse the repository at this point in the history
Signed-off-by: HashEngineering <[email protected]>
  • Loading branch information
HashEngineering committed Jan 12, 2024
1 parent 100c9cd commit 40606a7
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
12 changes: 11 additions & 1 deletion core/src/main/java/org/bitcoinj/crypto/BLSLazyPublicKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ protected void parse() throws ProtocolException {
length = cursor - offset;
}


@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
if (!initialized && buffer == null) {
Expand All @@ -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");
}
Expand Down Expand Up @@ -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;
}
}
}
24 changes: 24 additions & 0 deletions core/src/main/java/org/bitcoinj/crypto/BLSLazySignature.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}
}
}
2 changes: 1 addition & 1 deletion core/src/main/java/org/bitcoinj/crypto/BLSSignature.java
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public boolean recover(ArrayList<BLSSignature> sigs, ArrayList<BLSId> 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
Expand Down
33 changes: 16 additions & 17 deletions core/src/main/java/org/bitcoinj/quorums/FinalCommitment.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -56,11 +55,11 @@ public class FinalCommitment extends SpecialTxPayload {
ArrayList<Boolean> signers;
ArrayList<Boolean> 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) {
Expand Down Expand Up @@ -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 +
Expand All @@ -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;
Expand Down Expand Up @@ -293,7 +292,7 @@ public boolean verify(StoredBlock block, ArrayList<Masternode> 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<BLSPublicKey> memberPubKeys = Lists.newArrayList();
for (int i = 0; i < members.size(); i++) {
Expand All @@ -303,15 +302,15 @@ public boolean verify(StoredBlock block, ArrayList<Masternode> 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;
}
Expand Down Expand Up @@ -393,19 +392,19 @@ public LLMQParameters.LLMQType getLlmqType() {
}

public BLSPublicKey getQuorumPublicKey() {
return quorumPublicKey;
return quorumPublicKey.getPublicKey();
}

public Sha256Hash getQuorumVvecHash() {
return quorumVvecHash;
}

public BLSSignature getMembersSignature() {
return membersSignature;
return membersSignature.getSignature();
}

public BLSSignature getQuorumSignature() {
return quorumSignature;
return quorumSignature.getSignature();
}

public ArrayList<Boolean> getSigners() {
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/org/bitcoinj/quorums/Quorum.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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());
Expand Down

0 comments on commit 40606a7

Please sign in to comment.