Help language development. Donate to The Perl Foundation

Bitcoin::Core::Secp256k1 zef:knarkhov last updated on 2021-12-11

t/01.t
use v6.d;
use Test;
use Test::Mock;

use Bitcoin::Core::Secp256k1;

plan 4;

use-ok 'Bitcoin::Core::Secp256k1';

my $secp256k1 = Bitcoin::Core::Secp256k1.new;

subtest {
    plan 7;

    my $data = {
        key => '6fcc37ea5e9e09fec6c83e5fbd7a745e3eee81d16ebd861c9e66f55518c19798',
        msg => '1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8'
    };

    ok $secp256k1.verify_private_key(:privkey($data<key>)),  'privkey verified';

    my $pubkey = $secp256k1.create_public_key(:privkey($data<key>));
    my $pk = $secp256k1.compressed_public_key(:pubkey($pubkey));

    ok $pk, 'compressed pubkey defined';
    is $pk.bytes, 33, 'compressed pubkey length';
    is-deeply $pk, buf8.new(0x03, 0x1d, 0xd0, 0xa4, 0xe0, 0xdd, 0x8f, 0xf0, 0x95, 0xd9, 0xea, 0x3c, 0xc7, 0x41, 0xc9, 0x77, 0x37, 0x58, 0xf3, 0xb3, 0x90, 0xbd, 0x69, 0xd8, 0x2e, 0x89, 0x31, 0xd2, 0xb2, 0x76, 0xca, 0xd1, 0x86), 'compressed pubkey verified';

    my $signature      = $secp256k1.ecdsa_sign(:privkey($data<key>), :msg($data<msg>));
    my $normalized_sig = $secp256k1.signature_normalize(:sig($signature));

    ok $secp256k1.verify_ecdsa_sign(:pubkey($pubkey), :msg($data<msg>), :sig($normalized_sig)), 'signature verified';

    my $compact_sig = $secp256k1.signature_serialize(:sig($normalized_sig));

    is-deeply $normalized_sig, buf8.new(0x76, 0x97, 0x61, 0xB5, 0xE2, 0x48, 0x8E, 0x38, 0x72, 0x6B, 0x8E, 0xB0, 0xD4, 0xE3, 0xFA, 0x80, 0xDF, 0xFE, 0x46, 0x53, 0x80, 0x74, 0xCB, 0x1C, 0x29, 0x5C, 0x1D, 0x7C, 0x6F, 0x64, 0x1F, 0x2F, 0x02, 0x50, 0x7D, 0x2D, 0x0B, 0x3D, 0x3B, 0xB1, 0x91, 0x6E, 0xF6, 0x5F, 0x4C, 0x2D, 0x37, 0x9A, 0x37, 0x8A, 0x07, 0xC2, 0x0A, 0x30, 0xD4, 0x3C, 0x4E, 0x0C, 0xC2, 0x89, 0xAE, 0x50, 0xFB, 0x1C), 'signature buffer verified';
    is-deeply $compact_sig, buf8.new(0x2f, 0x1f, 0x64, 0x6f, 0x7c, 0x1d, 0x5c, 0x29, 0x1c, 0xcb, 0x74, 0x80, 0x53, 0x46, 0xfe, 0xdf, 0x80, 0xfa, 0xe3, 0xd4, 0xb0, 0x8e, 0x6b, 0x72, 0x38, 0x8e, 0x48, 0xe2, 0xb5, 0x61, 0x97, 0x76, 0x1c, 0xfb, 0x50, 0xae, 0x89, 0xc2, 0x0c, 0x4e, 0x3c, 0xd4, 0x30, 0x0a, 0xc2, 0x07, 0x8a, 0x37, 0x9a, 0x37, 0x2d, 0x4c, 0x5f, 0xf6, 0x6e, 0x91, 0xb1, 0x3b, 0x3d, 0x0b, 0x2d, 0x7d, 0x50, 0x02), 'compact signature buffer verified';
}, 'Secp256k1 create, sign, verify tests on predefined pubkey and msg';

subtest {
    plan 1;
    
    my UInt $iterations = 100;
    my Bool $subtestok  = True;

    for ^$iterations {
        my $data = {
            key => random32bytes(),
            msg => random32bytes()
        };

        if $secp256k1.verify_private_key(:privkey($data<key>)) {
            my $pubkey = $secp256k1.create_public_key(:privkey($data<key>));
            my $pk = $secp256k1.compressed_public_key(:pubkey($pubkey));

            my $signature      = $secp256k1.ecdsa_sign(:privkey($data<key>), :msg($data<msg>));
            my $normalized_sig = $secp256k1.signature_normalize(:sig($signature));

            if !$secp256k1.verify_ecdsa_sign(:pubkey($pubkey), :msg($data<msg>), :sig($normalized_sig)) {
                $subtestok = False;

                last;
            }

        }
        else {
            $subtestok = False;

            last;
        }
    }

    ok $subtestok, sprintf("checked %d random private keys and signatures", $iterations);
}, 'Secp256k1 create, sign, verify tests on pre-defined privkey and msg';

subtest {
    plan 1;

    my $data = {
        key => '6fcc37ea5e9e09fec6c83e5fbd7a745e3eee81d16ebd861c9e66f55518c19798',
        msg => '1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8'
    };

    my $secp256k1 = Bitcoin::Core::Secp256k1.new;
    my $signature = $secp256k1.ecdsa_sign(:privkey($data<key>), :msg($data<msg>));

    is $signature.bytes, 64, 'signature length';
}, 'README Synopsys';

done-testing;

sub random32bytes returns Str {
    my $buffer = buf8.new;

    while $buffer.bytes < 32 {
        $buffer.push(255.rand.Int || 0xff);
    }

    return $buffer.map({$_ < 16 ?? '0' ~ $_.base(16) !! $_.base(16)}).join(q{}).lc;
}