Skip to content

Commit

Permalink
Temporary handling infinite pubkey/signature as a special case until s…
Browse files Browse the repository at this point in the history
  • Loading branch information
Nashatyrev committed Jul 27, 2020
1 parent acebcca commit db88ac0
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 26 deletions.
7 changes: 7 additions & 0 deletions bls/src/main/java/tech/pegasys/teku/bls/BLS.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ public static boolean verify(BLSPublicKey publicKey, Bytes message, BLSSignature
return signature.getSignature().verify(publicKey.getPublicKey(), message);
}

public static BLSPublicKey aggregatePublicKeys(List<BLSPublicKey> publicKeys) {
return new BLSPublicKey(
getBlsImpl()
.aggregatePublicKeys(
publicKeys.stream().map(BLSPublicKey::getPublicKey).collect(Collectors.toList())));
}

/**
* Aggregates a list of BLSSignatures into a single BLSSignature.
*
Expand Down
35 changes: 24 additions & 11 deletions bls/src/main/java/tech/pegasys/teku/bls/impl/blst/BlstBLS12381.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ public static BlstSignature sign(BlstSecretKey secretKey, Bytes message) {
}

public static boolean verify(BlstPublicKey publicKey, Bytes message, BlstSignature signature) {
if (publicKey == BlstPublicKey.INFINITY || signature == BlstSignature.INFINITY) {
return publicKey == BlstPublicKey.INFINITY && signature == BlstSignature.INFINITY;
}
BLST_ERROR res =
blst.core_verify_pk_in_g1(
publicKey.ecPoint,
Expand Down Expand Up @@ -114,9 +117,13 @@ public BlstSignature aggregateSignatures(List<? extends Signature> signatures) {
}

@Override
public BlstBatchSemiAggregate prepareBatchVerify(
public BatchSemiAggregate prepareBatchVerify(
int index, List<? extends PublicKey> publicKeys, Bytes message, Signature signature) {
BlstPublicKey aggrPubKey = aggregatePublicKeys(publicKeys);
if (aggrPubKey == BlstPublicKey.INFINITY || signature == BlstSignature.INFINITY) {
return new BlstInfiniteSemiAggregate(
aggrPubKey == BlstPublicKey.INFINITY && signature == BlstSignature.INFINITY);
}
p2 g2Hash = HashToCurve.hashToG2(message);
p2_affine p2Affine = new p2_affine();
blst.p2_to_affine(p2Affine, g2Hash);
Expand All @@ -142,32 +149,38 @@ public BlstBatchSemiAggregate prepareBatchVerify(
}
blst.pairing_commit(ctx);

return new BlstBatchSemiAggregate(ctx);
return new BlstFiniteSemiAggregate(ctx);
}

@Override
public BlstBatchSemiAggregate prepareBatchVerify2(
public BatchSemiAggregate prepareBatchVerify2(
int index,
List<? extends PublicKey> publicKeys1,
Bytes message1,
Signature signature1,
List<? extends PublicKey> publicKeys2,
Bytes message2,
Signature signature2) {
BlstBatchSemiAggregate aggregate1 =
BatchSemiAggregate aggregate1 =
prepareBatchVerify(index, publicKeys1, message1, signature1);
BlstBatchSemiAggregate aggregate2 =
BatchSemiAggregate aggregate2 =
prepareBatchVerify(index + 1, publicKeys2, message2, signature2);
aggregate1.mergeWith(aggregate2);
aggregate2.release();

return aggregate1;
return BlstFiniteSemiAggregate.merge(aggregate1, aggregate2);
}

@Override
public boolean completeBatchVerify(List<? extends BatchSemiAggregate> preparedList) {
List<BlstBatchSemiAggregate> blstList =
preparedList.stream().map(b -> (BlstBatchSemiAggregate) b).collect(Collectors.toList());
boolean anyInvalidDummy = preparedList.stream()
.filter(a -> a instanceof BlstInfiniteSemiAggregate)
.map(a -> (BlstInfiniteSemiAggregate) a)
.anyMatch(a -> !a.isValid());

List<BlstFiniteSemiAggregate> blstList =
preparedList.stream()
.filter(a -> a instanceof BlstFiniteSemiAggregate)
.map(b -> (BlstFiniteSemiAggregate) b)
.collect(Collectors.toList());

if (blstList.isEmpty()) {
return true;
Expand All @@ -182,7 +195,7 @@ public boolean completeBatchVerify(List<? extends BatchSemiAggregate> preparedLi

int boolRes = blst.pairing_finalverify(ctx0, null);
blstList.get(0).release();
return mergeRes && boolRes != 0;
return mergeRes && boolRes != 0 && !anyInvalidDummy;
}

private static BigInteger nextBatchRandomMultiplier() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,38 @@
import tech.pegasys.teku.bls.impl.blst.swig.blst;
import tech.pegasys.teku.bls.impl.blst.swig.pairing;

public final class BlstBatchSemiAggregate implements BatchSemiAggregate {
final class BlstFiniteSemiAggregate implements BatchSemiAggregate {

public static BatchSemiAggregate merge(BatchSemiAggregate agg1, BatchSemiAggregate agg2) {
if (agg1 instanceof BlstFiniteSemiAggregate) {
if (agg2 instanceof BlstFiniteSemiAggregate) {
((BlstFiniteSemiAggregate) agg1).mergeWith((BlstFiniteSemiAggregate) agg2);
((BlstFiniteSemiAggregate) agg2).release();
return agg1;
} else {
if (((BlstInfiniteSemiAggregate)agg2).isValid()) {
return agg1;
} else {
((BlstFiniteSemiAggregate) agg1).release();
return agg2;
}
}
} else {
if (((BlstInfiniteSemiAggregate)agg1).isValid()) {
return agg2;
} else {
if (agg2 instanceof BlstFiniteSemiAggregate) {
((BlstFiniteSemiAggregate) agg2).release();
}
return agg1;
}
}
}

private final pairing ctx;
private boolean released = false;

BlstBatchSemiAggregate(pairing ctx) {
BlstFiniteSemiAggregate(pairing ctx) {
this.ctx = ctx;
}

Expand All @@ -36,7 +63,7 @@ void release() {
ctx.delete();
}

void mergeWith(BlstBatchSemiAggregate other) {
void mergeWith(BlstFiniteSemiAggregate other) {
BLST_ERROR ret = blst.pairing_merge(getCtx(), other.getCtx());
if (ret != BLST_ERROR.BLST_SUCCESS) {
throw new IllegalStateException("Error merging Blst pairing contexts: " + ret);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package tech.pegasys.teku.bls.impl.blst;

import tech.pegasys.teku.bls.BatchSemiAggregate;

final class BlstInfiniteSemiAggregate implements BatchSemiAggregate {
private final boolean isValid;

public BlstInfiniteSemiAggregate(boolean isValid) {
this.isValid = isValid;
}

public boolean isValid() {
return isValid;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes48;
import tech.pegasys.teku.bls.impl.PublicKey;
Expand All @@ -29,6 +30,29 @@ public class BlstPublicKey implements PublicKey {
private static final int COMPRESSED_PK_SIZE = 48;
private static final int UNCOMPRESSED_PK_LENGTH = 96;

static final Bytes48 INFINITY_COMPRESSED_BYTES =
Bytes48.fromHexString(
"0x"
+ "c0000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000");

static final BlstPublicKey INFINITY =
new BlstPublicKey(null) {
@Override
public void forceValidation() {}

@Override
public Bytes48 toBytesCompressed() {
return INFINITY_COMPRESSED_BYTES;
}

@Override
public Bytes toBytesUncompressed() {
throw new UnsupportedOperationException();
}
};

public static BlstPublicKey fromBytesUncompressed(Bytes uncompressed) {
checkArgument(uncompressed.size() == UNCOMPRESSED_PK_LENGTH);
p1_affine ecPoint = new p1_affine();
Expand All @@ -41,6 +65,9 @@ public static BlstPublicKey fromBytesUncompressed(Bytes uncompressed) {
}

public static BlstPublicKey fromBytes(Bytes48 compressed) {
if ((compressed.equals(INFINITY_COMPRESSED_BYTES))) {
return INFINITY;
}
p1_affine ecPoint = new p1_affine();
if (blst.p1_uncompress(ecPoint, compressed.toArrayUnsafe()) == BLST_ERROR.BLST_SUCCESS) {
return new BlstPublicKey(ecPoint);
Expand All @@ -53,10 +80,16 @@ public static BlstPublicKey fromBytes(Bytes48 compressed) {
public static BlstPublicKey aggregate(List<BlstPublicKey> publicKeys) {
checkArgument(publicKeys.size() > 0);

List<BlstPublicKey> finitePublicKeys =
publicKeys.stream().filter(pk -> pk != BlstPublicKey.INFINITY).collect(Collectors.toList());
if (finitePublicKeys.isEmpty()) {
return BlstPublicKey.INFINITY;
}

p1 sum = new p1();
blst.p1_from_affine(sum, publicKeys.get(0).ecPoint);
for (int i = 1; i < publicKeys.size(); i++) {
blst.p1_add_affine(sum, sum, publicKeys.get(i).ecPoint);
blst.p1_from_affine(sum, finitePublicKeys.get(0).ecPoint);
for (int i = 1; i < finitePublicKeys.size(); i++) {
blst.p1_add_affine(sum, sum, finitePublicKeys.get(i).ecPoint);
}
p1_affine res = new p1_affine();
blst.p1_to_affine(res, sum);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,17 @@
import tech.pegasys.teku.bls.impl.blst.swig.scalar;

public class BlstSecretKey implements SecretKey {
static final BlstSecretKey ZERO_SK = BlstSecretKey.fromBytesRaw(Bytes32.ZERO);

public static BlstSecretKey fromBytes(Bytes32 bytes) {
if (bytes.isZero()) {
return ZERO_SK;
} else {
return fromBytesRaw(bytes);
}
}

private static BlstSecretKey fromBytesRaw(Bytes32 bytes) {
scalar scalarVal = new scalar();
blst.scalar_from_bendian(scalarVal, bytes.toArrayUnsafe());
return new BlstSecretKey(scalarVal);
Expand Down Expand Up @@ -56,6 +65,9 @@ public Bytes32 toBytes() {

@Override
public Signature sign(Bytes message) {
if (this == ZERO_SK) {
return BlstSignature.INFINITY;
}
return BlstBLS12381.sign(this, message);
}

Expand All @@ -67,6 +79,9 @@ public void destroy() {

@Override
public BlstPublicKey derivePublicKey() {
if (this == ZERO_SK) {
return BlstPublicKey.INFINITY;
}
p1 pk = new p1();
blst.sk_to_pk_in_g1(pk, getScalarVal());
p1_affine pkAffine = new p1_affine();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.tuweni.bytes.Bytes;
import tech.pegasys.teku.bls.BatchSemiAggregate;
import tech.pegasys.teku.bls.impl.PublicKey;
import tech.pegasys.teku.bls.impl.PublicKeyMessagePair;
import tech.pegasys.teku.bls.impl.Signature;
Expand All @@ -33,7 +34,24 @@
public class BlstSignature implements Signature {
private static final int COMPRESSED_SIG_SIZE = 96;

private static final Bytes INFINITY_BYTES =
Bytes.fromHexString(
"0x"
+ "c000000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000000000");
static final BlstSignature INFINITY;

static {
p2_affine ec2Point = new p2_affine();
blst.p2_uncompress(ec2Point, INFINITY_BYTES.toArrayUnsafe());
INFINITY = new BlstSignature(ec2Point, true);
}

public static BlstSignature fromBytes(Bytes compressed) {
if (compressed.equals(INFINITY_BYTES)) {
return INFINITY;
}
checkArgument(
compressed.size() == COMPRESSED_SIG_SIZE,
"Expected " + COMPRESSED_SIG_SIZE + " bytes of input but got %s",
Expand All @@ -44,17 +62,22 @@ public static BlstSignature fromBytes(Bytes compressed) {
}

public static BlstSignature aggregate(List<BlstSignature> signatures) {
List<BlstSignature> finiteSignatures =
signatures.stream()
.filter(sig -> sig != BlstSignature.INFINITY)
.collect(Collectors.toList());

Optional<BlstSignature> invalidSignature =
signatures.stream().filter(s -> !s.isValid).findFirst();
finiteSignatures.stream().filter(s -> !s.isValid).findFirst();
if (invalidSignature.isPresent()) {
throw new IllegalArgumentException(
"Can't aggregate invalid signature: " + invalidSignature.get());
}

p2 sum = new p2();
blst.p2_from_affine(sum, signatures.get(0).ec2Point);
for (int i = 1; i < signatures.size(); i++) {
blst.p2_add_affine(sum, sum, signatures.get(i).ec2Point);
blst.p2_from_affine(sum, finiteSignatures.get(0).ec2Point);
for (int i = 1; i < finiteSignatures.size(); i++) {
blst.p2_add_affine(sum, sum, finiteSignatures.get(i).ec2Point);
}
p2_affine res = new p2_affine();
blst.p2_to_affine(res, sum);
Expand Down Expand Up @@ -85,11 +108,11 @@ public Bytes toBytesUncompressed() {
@Override
public boolean verify(List<PublicKeyMessagePair> keysToMessages) {

List<BlstBatchSemiAggregate> semiAggregates = new ArrayList<>();
List<BatchSemiAggregate> semiAggregates = new ArrayList<>();
for (int i = 0; i < keysToMessages.size(); i++) {
BlstPublicKey publicKey = (BlstPublicKey) keysToMessages.get(i).getPublicKey();
Bytes message = keysToMessages.get(i).getMessage();
BlstBatchSemiAggregate semiAggregate =
BatchSemiAggregate semiAggregate =
BlstBLS12381.INSTANCE.prepareBatchVerify(
i, Collections.singletonList(publicKey), message, this);
semiAggregates.add(semiAggregate);
Expand Down

0 comments on commit db88ac0

Please sign in to comment.