-
Notifications
You must be signed in to change notification settings - Fork 0
ABE Benchmarking Tutorial
This tutorial will teach you how the ABE Benchmarks work, and how you can create benchmarks for your own ABE schemes implemented using the upb.crypto
libraries.
Specifically, any scheme which wants to use this benchmark must implement the PredicateEncryptionScheme
interface from the CRACO library.
The tutorial will first give an overview of the capabilities and java classes involved. It will then guide you through creating an example benchmark for the Large Universe CP-ABE scheme of Waters, 2011. The scheme itself is included in the upb.crypto.craco
library.
The ABE benchmarking code is contained in the test/java
folder of the project, in the de.upb.crypto.craco.abe
package. Here, you can see a number of existing benchmarks for different ABE schemes included in the CRACO library, as well as a generic
package.
The generic
package includes the java classes used by the benchmarks. Let's take a look at what each of them do.
This includes the benchmarking code itself. Its constructor takes a ABEBenchmarkConfig
and ABEBenchmarkParams
instances which are used to configure the benchmark. To run the benchmark, the doBenchmark()
method is used. It will repeatedly run setup, key generation, and encryption and decryption and measure their execution times. At the end, averages will be printed.
This class is mostly for (theoretically) scheme-independent configuration of the benchmark. Here you can set things like number of warmup runs, the number of different setups, the number of key generations per setup, and number of encryptions/decryptions per key generation. Furthermore, you can configure whether this benchmark is for a ciphertext-policy or key-policy scheme.
The printDetails
attribute determines whether execution times are printed during the benchmark. If set to false
, only average executiom times will be printed in the summary after the benchmark.
Lastly, you can specify pairs of attributes/policies. The benchmark will run a benchmark per such pair and later split up the result per pair. This way you can test different number of attributes.
Since the ABEBenchmarkConfig
class has a lot of attributes, a builder pattern is used to build ABEBechmarkConfig
instances. Instead of instantiating ABEBenchmarkConfig
objects directly, you can use this class to build up such an object, and use the buildConfig()
method to obtain an instantiation with your previously selected settings (using the setX()
methods).
The attribute/policy pairs are specified using instances of this class. Additionally, a name can be given to such a pair, this will make it easier to distinguish the benchmark results later.
The benchmark code requires the scheme to implement the PredicateEncryptionScheme
interface. This interface does not provide methods for public parameter/master secret setup. Furthermore, the benchmark needs plaintexts to benchmark encryption/decryption.
Hence, this (abstract) class is used to specify how to perform the setup using the doSetup()
method. doSetup()
takes as argument a KeyIndex
and CiphertextIndex
object. This is in case the scheme needs access to the attributes/policy for setup. Whether KeyIndex
or CiphertextIndex
contains attributes or policy depends on the type of scheme set by the isCPABE
attribute set in the ABEBenchmarkConfig
used by the ABEBenchmark
.
generatePlainText
supplies the benchmark with fresh plaintexts for benchmarking encryption/decryption.
To create your own benchmark, you will need to extend this class and supply the aforementioned methods.
To create a benchmark for any scheme, we first need to create a subclass of ABEBenchmarkParams
. Create a new class file in the de.upb.crypto.craco.abe
package, called ABEWat11BenchmarkParams
and make it extend ABEBenchmarkParams
.
Next, we need to implement the abstract doSetup()
method.
@Override
public void doSetup(KeyIndex kIndex, CiphertextIndex cIndex) {
ABECPWat11Setup cpSetup = new ABECPWat11Setup();
cpSetup.doKeyGenRandomOracle(60);
ABECPWat11PublicParameters pp = cpSetup.getPublicParameters();
this.setScheme(new ABECPWat11(pp));
this.setMasterSecret(cpSetup.getMasterSecret());
this.setPublicParameters(pp);
}
As you can see, we run setup of the scheme in the first two lines of the method body. Then we retrieve the public parameters and set the scheme
, masterSecret
and publicParameters
attributes of our object. Setting publicParameters
is not necessary for the benchmark; however, it will be necessary for generating new plaintexts. Setting scheme
and masterSecret
is necessary, as the benchmark cannot run without them.
Furthermore, we did not use the method arguments of doSetup
. This scheme does not require knowledge of the attributes/policy for setup. Other schemes may differ in this regard, for example the small universe CP-ABE construction by Waters, 2011.
Lastly, we need to add the generatePlainText
method. We simply choose a random plaintext element. Here, we need the public parameters to get the target group.
@Override
public PlainText generatePlainText() {
return new GroupElementPlainText(
((ABECPWat11PublicParameters) this.getPublicParameters()).getGroupGT().getUniformlyRandomNonNeutral()
);
}
The finished class looks as follows (not including imports or package declaration).
public class ABEWat11BenchmarkParams extends ABEBenchmarkParams {
@Override
public void doSetup(KeyIndex kIndex, CiphertextIndex cIndex) {
ABECPWat11Setup cpSetup = new ABECPWat11Setup();
cpSetup.doKeyGenRandomOracle(60);
ABECPWat11PublicParameters pp = cpSetup.getPublicParameters();
this.setScheme(new ABECPWat11(pp));
this.setMasterSecret(cpSetup.getMasterSecret());
this.setPublicParameters(pp);
}
@Override
public PlainText generatePlainText() {
return new GroupElementPlainText(
((ABECPWat11PublicParameters) this.getPublicParameters()).getGroupGT().getUniformlyRandomNonNeutral()
);
}
}
Next we need to create some code we can run to call the benchmark and construct the ABEBenchmarkConfig
object. To do this, we create an ABEWat11Benchmark
class with a main
method we can run. We can already instantiate our params we just created.
public class ABEWat11Benchmark {
public static void main(String[] args) {
ABEBenchmarkParams params = new ABEWat11BenchmarkParams();
}
}
To run the benchmark code, we also need a ABEBenchmarkConfig
object. To instantiate this, we make use of the ABEBenchmarkConfigBuilder
. To starto ff, we just want a simple configuration, with default values.
public static void main(String[] args) {
ABEBenchmarkParams params = new ABEWat11BenchmarkParams();
ABEBenchmarkConfig config = new ABEBenchmarkConfigBuilder().setIsCPABE(true).buildConfig();
}
The setIsCPABe
is the only required call to ABEBenchmarkConfigBuilder
since otherwise the benchmark does not know whether we are testing a CP-ABE and KP-ABE. Since the scheme we are benchmarking is a CP-ABE scheme, we set it to true
. The rest of the values will be set to default.
Now, the only thing that is missing is running the benchmark itself.
public static void main(String[] args) {
ABEBenchmarkParams params = new ABEWat11BenchmarkParams();
ABEBenchmarkConfig config = new ABEBenchmarkConfigBuilder().setIsCPABE(true).buildConfig();
ABEBenchmark benchmark = new ABEBenchmark(params, config);
benchmark.doBenchmark();
}
Run the main
method. It will take a couple seconds. During the benchmarking, execution times and further information about the current benchmark runs will be printed to the console. After the benchmark, a summary with average execution times will be printed for each attribute/policy pair. As you can see, the default attribute/policy selection consists of attribute sizes from 2 to 128 (growing exponentially) and boolean policies consisting of exclusively AND and exclusively OR gates.
So far, our configuration of the benchmark is quite meager. Let's expand it. To explain the different options, we will have to take a look at how the benchmark works.
This can be seen by looking at the console output during the benchmark.
-- Selected attribute/policy '128 BigInt ALL AND gates' --
-- Benchmark Run 0 --
Setup: Total execution time: 134ms
-- Performing Key Generation Number 0 --
EncryptionKey Generation: Total execution time: 0ms
DecryptionKey Generation: Total execution time: 6279ms
-- Performing Encrypt/Decrypt Cycle 0 --
Encryption: Total execution time: 3925ms
Decryption: Total execution time: 2514ms
Encryption/Decryption correct: true
-- Selected attribute/policy '128 BigInt ALL OR gates' --
-- Benchmark Run 0 --
Setup: Total execution time: 130ms
-- Performing Key Generation Number 0 --
EncryptionKey Generation: Total execution time: 0ms
DecryptionKey Generation: Total execution time: 6060ms
-- Performing Encrypt/Decrypt Cycle 0 --
Encryption: Total execution time: 4027ms
Decryption: Total execution time: 105ms
Encryption/Decryption correct: true
As you can see, for each attribute/policy pair, a number of benchmark runs are performed. This number is determined by the numSetup
attribute of the ABEBenchmarkConfig
object used. For each benchmark run, the scheme is newly setup using our previously defined doSetup()
method.
For each setup, a number of key generations are performed, the number of which is determined by the numKeyGenerations
attribute.
Lastly, for each key generation, a plaintext is generated using the generatePlainText()
method, encrypted, and then decrypted again. We also test whether the decryption succeeded as a correctness check. The number of such plaintext-generation/encryption/decryption cycles is determined by the encDecCycles
attribute.
So, lets reconfigure our benchmark.
public static void main(String[] args) {
ABEBenchmarkParams params = new ABEWat11BenchmarkParams();
ABEBenchmarkConfigBuilder configBuilder = new ABEBenchmarkConfigBuilder().setIsCPABE(true);
configBuilder.setNumSetups(2);
configBuilder.setNumKeyGenerations(2);
configBuilder.setNumEncDecCycles(2);
ABEBenchmarkConfig config = configBuilder.buildConfig();
ABEBenchmark benchmark = new ABEBenchmark(params, config);
benchmark.doBenchmark();
}
Since we have increased the number of runs, the benchmark should now take longer.
Of course, you may not want to use the default selection of attribute/policy pairs. The ABEBenchmarkConfigBuilder
object's setSetOfAttributesPolcyNameTriples()
method accepts an array of name/attributes/policy triples which will then be used in the benchmark instead of the default selection.
You can also change the number of warmup runs. A warmup run just simply does one run through each of setup, key generation, and one encryption/decryption cycle.
If you don't want your console to be cluttered during the benchmark, you can also disable most of the printing by using setPrintDetails(false)
.
Depending on the scheme, unless you specify a specific bilinear group, the setup algorithm will probably make use of the bilinear group selection of the upb.crypto.math
library. It will select a pairing of the right type providing the given security level. However, the pairings provided there are quite inefficient. If you want, you can instead use our wrapper around the efficient BN264 pairing from the mcl library.
Keep in mind that this is a type 3 pairing.