Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tkn20 benchmarks #442

Merged
merged 1 commit into from
Jun 1, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
265 changes: 265 additions & 0 deletions abe/cpabe/tkn20/bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
package tkn20

import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"fmt"
"strconv"
"strings"
"testing"

"golang.org/x/crypto/nacl/box"
)

type abeTestCase struct {
desc string
attrs Attributes
policy Policy
msk SystemSecretKey
pk PublicKey
}

var testCases []abeTestCase

var (
msg = []byte("drink your ovaltine now")
longMsg = []byte(strings.Repeat("a", 10000))
)

func generateAttrs() Attributes {
benchableAttrs := make(map[string]string, 50)
for i := 0; i < 50; i++ {
benchableAttrs["k"+strconv.Itoa(i)] = "v" + strconv.Itoa(i)
}
attrs := Attributes{}
attrs.FromMap(benchableAttrs)
return attrs
}

func generatePolicy() string {
var policyBuilder strings.Builder
for i := 0; i < 50; i++ {
policyBuilder.WriteString("k")
policyBuilder.WriteString(strconv.Itoa(i))
policyBuilder.WriteString(":v")
policyBuilder.WriteString(strconv.Itoa(i))
if i != 49 {
if i%2 == 0 {
policyBuilder.WriteString(" and ")
} else {
policyBuilder.WriteString(" or ")
}
}
}
return policyBuilder.String()
}

func init() {
smallPolicy := Policy{}
_ = smallPolicy.FromString("(k1:v1 or k1:v2) and not k2:v3")
smallAttrs := Attributes{}
smallAttrs.FromMap(map[string]string{"k1": "v2", "k2": "v4"})
longPolicy := Policy{}
_ = longPolicy.FromString(generatePolicy())
testCases = []abeTestCase{
{
desc: "smallPolicy/Attrs",
attrs: smallAttrs,
policy: smallPolicy,
},
{
desc: "longPolicy/Attrs",
attrs: generateAttrs(),
policy: longPolicy,
},
}
var err error
for i := range testCases {
testCases[i].pk, testCases[i].msk, err = Setup(rand.Reader)
if err != nil {
panic(err)
}
}
}

func BenchmarkTKN20KeyGen(b *testing.B) {
for _, tc := range testCases {
b.Run(fmt.Sprintf("keygen:%s", tc.desc), func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := tc.msk.KeyGen(rand.Reader, tc.attrs)
if err != nil {
b.Fatal(err)
}
}
})
}
}

func BenchmarkRSAKeyGen(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
b.Fatal(err)
}
}
}

func BenchmarkX25519KeyGen(b *testing.B) {
for i := 0; i < b.N; i++ {
_, _, err := box.GenerateKey(rand.Reader)
if err != nil {
b.Fatal(err)
}
}
}

func BenchmarkTKN20Encrypt(b *testing.B) {
for _, tc := range testCases {
b.Run(fmt.Sprintf("encrypt:%s", tc.desc), func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := tc.pk.Encrypt(rand.Reader, tc.policy, msg)
if err != nil {
b.Fatal(err)
}
}
})
}
}

func BenchmarkRSAEncrypt(b *testing.B) {
privKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
b.Fatal(err)
}
pubKey := privKey.PublicKey
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := rsa.EncryptPKCS1v15(rand.Reader, &pubKey, msg)
if err != nil {
b.Fatal(err)
}
}
}

func BenchmarkX25519Encrypt(b *testing.B) {
pubKey, _, err := box.GenerateKey(rand.Reader)
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := box.SealAnonymous(nil, msg, pubKey, rand.Reader)
if err != nil {
b.Fatal(err)
}
}
}

func BenchmarkTKN20Decrypt(b *testing.B) {
for _, tc := range testCases {
b.Run(fmt.Sprintf("decrypt:%s", tc.desc), func(b *testing.B) {
userKey, err := tc.msk.KeyGen(rand.Reader, tc.attrs)
if err != nil {
b.Fatal(err)
}
ciphertext, err := tc.pk.Encrypt(rand.Reader, tc.policy, msg)
if err != nil {
b.Fatal(err)
}
keyBytes, _ := userKey.MarshalBinary()
pubKeyBytes, _ := tc.pk.MarshalBinary()
// longCt is only benchmarked to measure size overhead
longCt, err := tc.pk.Encrypt(rand.Reader, tc.policy, longMsg)
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err = userKey.Decrypt(ciphertext)
if err != nil {
b.Fatal(err)
}
}
b.ReportMetric(float64(len(pubKeyBytes)), "public_key_size")
b.ReportMetric(float64(len(keyBytes)), "attribute_secret_key_size")
b.ReportMetric(float64(len(ciphertext)-len(msg)), "ciphertext_bytes_overhead_32b_msg")
b.ReportMetric(float64(len(longCt)-len(longMsg)), "ciphertext_bytes_overhead_10kb_msg")
})
}
}

func BenchmarkRSADecrypt(b *testing.B) {
privKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
b.Fatal(err)
}
pubKey := privKey.PublicKey
ct, err := rsa.EncryptPKCS1v15(rand.Reader, &pubKey, msg)
if err != nil {
b.Fatal(err)
}
// longCt is only benchmarked to measure size overhead
longCt, err := rsaEncrypt(longMsg, &privKey.PublicKey)
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := rsa.DecryptPKCS1v15(rand.Reader, privKey, ct)
if err != nil {
b.Fatal(err)
}
}
b.ReportMetric(float64(privKey.PublicKey.Size()), "public_key_size")
b.ReportMetric(float64(len(x509.MarshalPKCS1PrivateKey(privKey))), "secret_key_size")
b.ReportMetric(float64(len(ct)-len(msg)), "ciphertext_bytes_overhead")
b.ReportMetric(float64(len(longCt)-len(longMsg)), "ciphertext_bytes_overhead_10kb_msg")
}

func BenchmarkX25519Decrypt(b *testing.B) {
pubKey, privKey, err := box.GenerateKey(rand.Reader)
if err != nil {
b.Fatal(err)
}
ct, err := box.SealAnonymous(nil, msg, pubKey, rand.Reader)
if err != nil {
b.Fatal(err)
}
// longCt is only benchmarked to measure size overhead
longCt, err := box.SealAnonymous(nil, longMsg, pubKey, rand.Reader)
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, ok := box.OpenAnonymous(nil, ct, pubKey, privKey)
if !ok {
b.Fatal(err)
}
}
b.ReportMetric(float64(len(pubKey)), "public_key_size")
b.ReportMetric(float64(len(privKey)), "secret_key_size")
b.ReportMetric(float64(len(ct)-len(msg)), "ciphertext_bytes_overhead_32b_msg")
b.ReportMetric(float64(len(longCt)-len(longMsg)), "ciphertext_bytes_overhead_10kb_msg")
}

func rsaEncrypt(data []byte, pubKey *rsa.PublicKey) ([]byte, error) {
chunkSize := 245 // Max chunk size for 2048 bit key with PKCS1v15 padding
var ct []byte
for len(data) > 0 {
if len(data) < chunkSize {
chunkSize = len(data)
}
chunk := data[:chunkSize]
data = data[chunkSize:]
encryptedChunk, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, chunk)
if err != nil {
return nil, err
}
ct = append(ct, encryptedChunk...)
}
return ct, nil
}