Skip to content
This repository has been archived by the owner on Apr 23, 2019. It is now read-only.

Commit

Permalink
adding BLS12-381 sig verification and aggregation
Browse files Browse the repository at this point in the history
  • Loading branch information
jrhea committed Jan 21, 2019
1 parent 79e4a4d commit 8a7a46a
Show file tree
Hide file tree
Showing 18 changed files with 876 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -9,6 +9,7 @@
.classpath
.externalToolBuilders/
.gradle/
.vscode/
.idea/*
!.idea/codeStyles/
.loadpath
Expand Down
2 changes: 1 addition & 1 deletion crypto/build.gradle
Expand Up @@ -9,7 +9,7 @@ dependencies {
compile 'com.google.guava:guava'
compile 'com.github.jnr:jnr-ffi'
compileOnly 'org.bouncycastle:bcprov-jdk15on'

compile 'org.miracl.milagro.amcl:milagro-crypto-java'
testCompile project(':junit')
testCompile 'org.bouncycastle:bcprov-jdk15on'
testCompile 'org.junit.jupiter:junit-jupiter-api'
Expand Down
122 changes: 122 additions & 0 deletions crypto/src/main/java/net/consensys/cava/crypto/mikuli/BLS12381.java
@@ -0,0 +1,122 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package net.consensys.cava.crypto.mikuli;

import net.consensys.cava.crypto.mikuli.group.AtePairing;
import net.consensys.cava.crypto.mikuli.group.G1Point;
import net.consensys.cava.crypto.mikuli.group.G2Point;
import net.consensys.cava.crypto.mikuli.group.GTPoint;

import java.util.List;

import org.apache.milagro.amcl.BLS381.BIG;
import org.apache.milagro.amcl.BLS381.ECP;
import org.apache.milagro.amcl.BLS381.ECP2;
import org.apache.milagro.amcl.BLS381.MPIN;

public final class BLS12381 {

/**
* Generates a SignatureAndPublicKey.
*
* @param keyPair The public and private key pair, not null
* @param message The message to sign, not null
* @return The SignatureAndPublicKey, not null
*/
public static SignatureAndPublicKey sign(KeyPair keyPair, byte[] message) {
G2Point hashInGroup2 = hashFunction(message);
/*
* The signature is hash point in G2 multiplied by the private key.
*/
G2Point sig = keyPair.privateKey().sign(hashInGroup2);
return new SignatureAndPublicKey(new Signature(sig), keyPair.publicKey());
}

/**
* Verifies the given BLS signature against the message bytes using the public key.
*
* @param publicKey The public key, not null
* @param signature The signature, not null
* @param message The message data to verify, not null
*
* @return True if the verification is successful.
*/
public static boolean verify(PublicKey publicKey, Signature signature, byte[] message) {
G1Point g1Generator = SystemParameters.g1Generator;

G2Point hashInGroup2 = hashFunction(message);
GTPoint e1 = AtePairing.pair(publicKey.g1Point(), hashInGroup2);
GTPoint e2 = AtePairing.pair(g1Generator, signature.g2Point());

return e1.equals(e2);
}

/**
* Verifies the given BLS signature against the message bytes using the public key.
*
* @param sigAndPubKey The signature and public key, not null
* @param message The message data to verify, not null
*
* @return True if the verification is successful, not null
*/
public static boolean verify(SignatureAndPublicKey sigAndPubKey, byte[] message) {
return verify(sigAndPubKey.publicKey(), sigAndPubKey.signature(), message);
}

/**
* Aggregates list of Signature and PublicKey pairs
*
* @param sigAndPubKeyList The list of Signatures and corresponding Public keys to aggregate, not null
* @return SignatureAndPublicKey, not null
* @throws IllegalArgumentException if parameter list is empty
*/
public static SignatureAndPublicKey aggregate(List<SignatureAndPublicKey> sigAndPubKeyList) {
listNotEmpty(sigAndPubKeyList);
return sigAndPubKeyList.stream().reduce((a, b) -> a.combine(b)).get();
}

/**
* Aggregates list of PublicKey pairs
*
* @param publicKeyList The list of public keys to aggregate, not null
* @return PublicKey The public key, not null
* @throws IllegalArgumentException if parameter list is empty
*/
public static PublicKey aggregatePublicKey(List<PublicKey> publicKeyList) {
listNotEmpty(publicKeyList);
return publicKeyList.stream().reduce((a, b) -> a.combine(b)).get();
}

/**
* Aggregates list of Signature pairs
*
* @param signatureList The list of signatures to aggregate, not null
* @throws IllegalArgumentException if parameter list is empty
* @return Signature, not null
*/
public static Signature aggregateSignatures(List<Signature> signatureList) {
listNotEmpty(signatureList);
return signatureList.stream().reduce((a, b) -> a.combine(b)).get();
}

private static void listNotEmpty(List<?> list) {
if (list.isEmpty()) {
throw new IllegalArgumentException("Parameter list is empty");
}
}

private static G2Point hashFunction(byte[] message) {
byte[] hashByte = MPIN.HASH_ID(ECP.SHA256, message, BIG.MODBYTES);
return new G2Point(ECP2.mapit(hashByte));
}
}
35 changes: 35 additions & 0 deletions crypto/src/main/java/net/consensys/cava/crypto/mikuli/KeyPair.java
@@ -0,0 +1,35 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package net.consensys.cava.crypto.mikuli;

public final class KeyPair {

private final PrivateKey privateKey;
private final PublicKey publicKey;

KeyPair(PrivateKey privateKey, PublicKey publicKey) {
if (privateKey == null || publicKey == null) {
throw new NullPointerException("KeyPair was not properly initialized");
}
this.privateKey = privateKey;
this.publicKey = publicKey;
}

public PublicKey publicKey() {
return publicKey;
}

public PrivateKey privateKey() {
return privateKey;
}
}
@@ -0,0 +1,34 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package net.consensys.cava.crypto.mikuli;

import net.consensys.cava.crypto.mikuli.group.G1Point;
import net.consensys.cava.crypto.mikuli.group.Scalar;

import org.apache.milagro.amcl.BLS381.BIG;
import org.apache.milagro.amcl.RAND;

public final class KeyPairFactory {

static public KeyPair createKeyPair() {
G1Point g1Generator = SystemParameters.g1Generator;
RAND rng = new RAND();

Scalar secret = new Scalar(BIG.randomnum(SystemParameters.curveOrder, rng));

PrivateKey privateKey = new PrivateKey(secret);
G1Point g1Point = g1Generator.mul(secret);
PublicKey publicKey = new PublicKey(g1Point);
return new KeyPair(privateKey, publicKey);
}
}
@@ -0,0 +1,32 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package net.consensys.cava.crypto.mikuli;

import net.consensys.cava.crypto.mikuli.group.G2Point;
import net.consensys.cava.crypto.mikuli.group.Scalar;

public final class PrivateKey {

private final Scalar scalarValue;

PrivateKey(Scalar value) {
if (value == null) {
throw new NullPointerException("PrivateKey was not properly initialized");
}
this.scalarValue = value;
}

protected G2Point sign(G2Point message) {
return message.mul(scalarValue);
}
}
@@ -0,0 +1,75 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package net.consensys.cava.crypto.mikuli;

import net.consensys.cava.crypto.mikuli.group.G1Point;

public final class PublicKey {

private final G1Point point;

PublicKey(G1Point point) {
if (point == null) {
throw new NullPointerException("PublicKey was not properly initialized");
}
this.point = point;
}

public PublicKey combine(PublicKey pk) {
return new PublicKey(point.add(pk.point));
}

/**
* Public key serialization
*
* @return byte array representation of the public key
*/
public byte[] encode() {
return point.toBytes();
}

public static PublicKey decode(byte[] bytes) {
G1Point point = G1Point.fromBytes(bytes);
return new PublicKey(point);
}


@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((point == null) ? 0 : point.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PublicKey other = (PublicKey) obj;
if (point == null) {
if (other.point != null)
return false;
} else if (!point.equals(other.point))
return false;
return true;
}

public G1Point g1Point() {
return point;
}
}
@@ -0,0 +1,78 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package net.consensys.cava.crypto.mikuli;

import net.consensys.cava.crypto.mikuli.group.G2Point;

public final class Signature {
private final G2Point point;

Signature(G2Point point) {
if (point == null) {
throw new NullPointerException("Signature was not properly initialized");
}
this.point = point;
}

@Override
public String toString() {
return "Signature [ecpPoint=" + point.toString() + "]";
}

public Signature combine(Signature sig) {
return new Signature(point.add(sig.point));
}

/**
* Signature serialization
*
* @return byte array representation of the signature, not null
*/
public byte[] encode() {
return point.toBytes();
}

public static Signature decode(byte[] bytes) {
G2Point point = G2Point.fromBytes(bytes);
return new Signature(point);
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((point == null) ? 0 : point.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Signature other = (Signature) obj;
if (point == null) {
if (other.point != null)
return false;
} else if (!point.equals(other.point))
return false;
return true;
}

G2Point g2Point() {
return point;
}
}

0 comments on commit 8a7a46a

Please sign in to comment.