Improve RSA performance in Level 3 OEMCrypto

Merge from widevine repo of http://go/wvgerrit/14668

This CL modifies the multiplication routine to avoid memory cache
misses.  This shows a 10-20% speed improvment in license requests on
an x86.

Level 3 library version:
level3/arm/libwvlevel3.a  Level3 Library Jun 15 2015 14:09:24
level3/x86/libwvlevel3.a  Level3 Library Jun 15 2015 14:09:10

bug: 18252910

Change-Id: I4429324374de46d1d710d5fcac80f7ed363c696c
This commit is contained in:
Fred Gylys-Colwell
2015-06-17 11:28:27 -07:00
parent 82bf03f062
commit f9453190fd
3 changed files with 185 additions and 0 deletions

View File

@@ -7,6 +7,7 @@
#include <getopt.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <algorithm>
#include <iostream>
@@ -677,6 +678,11 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) {
if (!usage_table) FilterOut(&filter, "*UsageTable*");
if (derive_key_method == NO_METHOD) FilterOut(&filter, "*SessionTest*");
if (api_version < 10) FilterOut(&filter, "*API10*");
// Performance tests take a long time. Filter them out if they are not
// specifically requested.
if (filter.find("Performance") == std::string::npos) {
FilterOut(&filter, "*Performance*");
}
return filter;
}
@@ -2443,6 +2449,75 @@ TEST_F(OEMCryptoSessionTests, Decrypt) {
s.TestDecryptCTR();
}
TEST_F(OEMCryptoSessionTests, DecryptPerformance) {
OEMCryptoResult sts;
Session s;
s.open();
s.GenerateTestSessionKeys();
const time_t TestDuration = 5;
s.FillSimpleMessage(600, 0, 0);
s.EncryptAndSign();
s.LoadTestKeys();
vector<uint8_t> keyId = wvcdm::a2b_hex("000000000000000000000000");
sts = OEMCrypto_SelectKey(s.session_id(), &keyId[0], keyId.size());
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
vector<uint8_t> encryptionIv =
wvcdm::a2b_hex("719dbcb253b2ec702bb8c1b1bc2f3bc6");
const size_t max_length = 250*1000;
vector<uint8_t> input(max_length);
printf("Size of input is %zd\n", input.size());
for(unsigned int i=0; i < max_length; i++) input[i] = i % 256;
vector<uint8_t> output(max_length);
OEMCrypto_DestBufferDesc destBuffer;
destBuffer.type = OEMCrypto_BufferType_Clear;
destBuffer.buffer.clear.address = &output[0];
const char* level = OEMCrypto_SecurityLevel();
const int n = 10;
double x[n], y[n];
double xsum = 0.0;
double ysum = 0.0;
double xysum = 0.0;
double xsqsum = 0.0;
printf("PERF:head, security, bytes, bytes/frame, time(ms)/frame, bandwidth\n");
for(int i=0; i < n; i++) {
size_t length = 1000 + i*1000;
destBuffer.buffer.clear.max_length = length;
time_t test_start = time(NULL);
time_t test_end = time(NULL);
int count = 0;
size_t total = 0;
do {
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_DecryptCTR(
s.session_id(), &input[0], length, true,
&encryptionIv[0], 0, &destBuffer,
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
count++;
total += length;
test_end = time(NULL);
} while(test_end - test_start < TestDuration);
x[i] = length;
y[i] = 1000*(test_end-test_start)/((double)count);
xsum += x[i];
ysum += y[i];
xysum += x[i]*y[i];
xsqsum += x[i]*x[i];
printf("PERF:stat, %s, %12zd, %12g, %12g, %12g\n", level, total,
x[i], y[i],
((double)total)/((double)(test_end-test_start))
);
}
double b = (n*xysum - xsum*ysum) / (n*xsqsum - xsum*xsum);
double a = (ysum - b*xsum)/n;
printf("PERF-FIT, security=%s fit time(ms)/frame = %g + %g * buffer_size\n",
level, a, b);
for(int i=0; i < n; i++) {
printf("PERF-FIT, %12g, %12g, %12g\n", x[i], y[i], a + b*x[i]);
}
}
TEST_F(OEMCryptoSessionTests, DecryptZeroDuration) {
OEMCryptoResult sts;
Session s;
@@ -3003,6 +3078,116 @@ class OEMCryptoUsesCertificate : public OEMCryptoLoadsCertificate {
Session session_;
};
// Test performance
TEST_F( OEMCryptoLoadsCertificate, RSAPerformance) {
OEMCryptoResult sts;
sleep(2); // Make sure are not nonce limited.
const uint32_t TestDuration = 5000; // milliseconds.
struct timeval start_time, end_time;
gettimeofday(&start_time, NULL);
gettimeofday(&end_time, NULL);
double mtime = 0;
long count = 0;
for(int i=0; i< 15; i++) { // Only 20 nonce available.
vector<uint8_t> wrapped_key;
CreateWrappedRSAKey(&wrapped_key, kSign_RSASSA_PSS, true);
count++;
gettimeofday(&end_time, NULL);
long seconds = end_time.tv_sec - start_time.tv_sec;
long useconds = end_time.tv_usec - start_time.tv_usec;
mtime = seconds * 1e3 + useconds * 1e-3;
}
double provision_time = mtime / count;
std::vector<uint8_t> wrapped_rsa_key;
Session session;
CreateWrappedRSAKey(&wrapped_rsa_key, kSign_RSASSA_PSS, true);
gettimeofday(&start_time, NULL);
gettimeofday(&end_time, NULL);
mtime = 0;
count = 0;
do {
Session s;
s.open();
sts = OEMCrypto_LoadDeviceRSAKey(s.session_id(), &wrapped_rsa_key[0],
wrapped_rsa_key.size());
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
const size_t size = 50;
vector<uint8_t> licenseRequest(size);
OEMCrypto_GetRandom(&licenseRequest[0], licenseRequest.size());
size_t signature_length = 0;
sts = OEMCrypto_GenerateRSASignature(s.session_id(), &licenseRequest[0],
licenseRequest.size(), NULL,
&signature_length, kSign_RSASSA_PSS);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
ASSERT_NE(static_cast<size_t>(0), signature_length);
uint8_t* signature = new uint8_t[signature_length];
sts = OEMCrypto_GenerateRSASignature(s.session_id(), &licenseRequest[0],
licenseRequest.size(), signature,
&signature_length, kSign_RSASSA_PSS);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
count++;
gettimeofday(&end_time, NULL);
long seconds = end_time.tv_sec - start_time.tv_sec;
long useconds = end_time.tv_usec - start_time.tv_usec;
mtime = seconds * 1e3 + useconds * 1e-3;
} while(mtime < TestDuration);
double license_request_time = mtime / count;
Session s;
s.open();
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_LoadDeviceRSAKey(s.session_id(), &wrapped_rsa_key[0],
wrapped_rsa_key.size()));
vector<uint8_t> enc_session_key;
s.PreparePublicKey();
ASSERT_TRUE(s.GenerateRSASessionKey(&enc_session_key));
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
s.FillDefaultContext(&mac_context, &enc_context);
gettimeofday(&start_time, NULL);
gettimeofday(&end_time, NULL);
mtime = 0;
count = 0;
enc_session_key = wvcdm::a2b_hex(
"7789c619aa3b9fa3c0a53f57a4abc6"
"02157c8aa57e3c6fb450b0bea22667fb"
"0c3200f9d9d618e397837c720dc2dadf"
"486f33590744b2a4e54ca134ae7dbf74"
"434c2fcf6b525f3e132262f05ea3b3c1"
"198595c0e52b573335b2e8a3debd0d0d"
"d0306f8fcdde4e76476be71342957251"
"e1688c9ca6c1c34ed056d3b989394160"
"cf6937e5ce4d39cc73d11a2e93da21a2"
"fa019d246c852fe960095b32f120c3c2"
"7085f7b64aac344a68d607c0768676ce"
"d4c5b2d057f7601921b453a451e1dea0"
"843ebfef628d9af2784d68e86b730476"
"e136dfe19989de4be30a4e7878efcde5"
"ad2b1254f80c0c5dd3cf111b56572217"
"b9f58fc1dacbf74b59d354a1e62cfa0e"
"bf");
do {
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_DeriveKeysFromSessionKey(
s.session_id(), &enc_session_key[0], enc_session_key.size(),
&mac_context[0], mac_context.size(), &enc_context[0],
enc_context.size()));
count++;
gettimeofday(&end_time, NULL);
long seconds = end_time.tv_sec - start_time.tv_sec;
long useconds = end_time.tv_usec - start_time.tv_usec;
mtime = seconds * 1e3 + useconds * 1e-3;
} while(mtime < TestDuration);
double derive_keys_time = mtime / count;
const char* level = OEMCrypto_SecurityLevel();
printf("PERF:head, security, provision (ms), lic req(ms), derive keys(ms)\n");
printf("PERF:stat, %s, %8.3f, %8.3f, %8.3f\n", level, provision_time,
license_request_time, derive_keys_time);
}
TEST_F(OEMCryptoUsesCertificate, RSASignature) {
OEMCryptoResult sts;
// Sign a Message