aboutsummaryrefslogtreecommitdiff
path: root/test/BenchTest.mc
blob: df12db1fd38b9715d29e248176797870da5fb4f4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Author:  cirakg & claude ai
// Summary: Benchmarks of the crypto, OTP and storage code; logs BENCH lines for docs/PERFORMANCE.md, never fails.
//
// Simulator timings run on the PC's CPU, so they only compare primitives with
// each other (for example how much SHA-512 costs against native SHA-1).
// Watch timings come from the on-watch benchmark in M4.

import Toybox.Lang;
import Toybox.System;
import Toybox.Test;

(:test)
module Bench {
    // Run fn `times` times and log the average in microseconds.
    function measure(logger as Test.Logger, name as String, times as Number, fn as Method() as Void) as Void {
        var start = System.getTimer();
        for (var i = 0; i < times; i++) {
            fn.invoke();
        }
        var elapsed = System.getTimer() - start;
        logger.debug("BENCH " + name + " us_per_call=" + (elapsed * 1000 / times));
    }

    class Cases {
        var secret20 as ByteArray = new [20]b;
        var secret64 as ByteArray = new [64]b;
        var keys as SealedBox.Keys = new SealedBox.Keys(new [32]b);
        var box as ByteArray = []b;

        function initialize() {
            box = SealedBox.seal(keys, []b, new [20]b);
        }

        function totpSha1() as Void {
            Otp.totp(Hashes.SHA1, secret20, 1700000000l, 30, 6);
        }

        function totpSha256() as Void {
            Otp.totp(Hashes.SHA256, secret20, 1700000000l, 30, 6);
        }

        function totpSha512() as Void {
            Otp.totp(Hashes.SHA512, secret64, 1700000000l, 30, 6);
        }

        function pbkdf2Thousand() as Void {
            Kdf.pbkdf2([1, 2, 3, 4, 5, 6]b, new [16]b, 1000, 32);
        }

        function sealOpen() as Void {
            SealedBox.open(keys, []b, SealedBox.seal(keys, []b, new [20]b));
        }

        function selfTest() as Void {
            SelfTest.run();
        }
    }

    // A vault with 20 OTP entries, for list and open timings.
    class VaultCases {
        var vault as Vault;
        var ids as Array<String>;

        function initialize() {
            vault = new Vault(new MemoryBackend(), new FakeTime());
            for (var i = 0; i < 20; i++) {
                vault.add(StorageFixtures.totp("Entry " + i));
            }
            ids = vault.ids();
        }

        // What the list does on start-up: every header.
        function readAllHeaders() as Void {
            for (var i = 0; i < ids.size(); i++) {
                vault.header(ids[i]);
            }
        }

        // What showing one code does: decrypt one entry.
        function openOne() as Void {
            vault.open(ids[0]).wipeSecrets();
        }

        function addOne() as Void {
            var e = StorageFixtures.totp("Bench");
            vault.add(e);
            vault.remove(e.id);
        }
    }
}

(:test)
function benchmarkPrimitives(logger as Test.Logger) as Boolean {
    var c = new Bench.Cases();
    Bench.measure(logger, "totp_sha1", 20, c.method(:totpSha1));
    Bench.measure(logger, "totp_sha256", 20, c.method(:totpSha256));
    Bench.measure(logger, "totp_sha512", 20, c.method(:totpSha512));
    Bench.measure(logger, "pbkdf2_1000_iterations", 3, c.method(:pbkdf2Thousand));
    Bench.measure(logger, "sealedbox_seal_open", 20, c.method(:sealOpen));
    Bench.measure(logger, "self_test", 3, c.method(:selfTest));
    return true;
}

(:test)
function benchmarkVault(logger as Test.Logger) as Boolean {
    var v = new Bench.VaultCases();
    Bench.measure(logger, "vault_20_headers", 5, v.method(:readAllHeaders));
    Bench.measure(logger, "vault_open_entry", 20, v.method(:openOne));
    Bench.measure(logger, "vault_add_remove", 10, v.method(:addOne));
    return true;
}