The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/env perl

use Test::More;
use Math::BigInt try => 'GMP,Pari';
use strict;
use warnings;
no strict 'refs';

use lib '../lib';

our $module;
BEGIN {
    our $module = 'Crypt::MagicSignatures::Key';
    use_ok($module, qw/b64url_encode b64url_decode/);   # 1
};

my $test_msg = 'This is a small message test.';


# Check for broken Math::BigInt by
# https://salmon-protocol.googlecode.com/svn/trunk/
#   lib/python/magicsig_hjfreyer/magicsigalg_test.py
my $n = Math::BigInt->new(2)->bpow(2048)->badd(42);
my $test_n = Math::BigInt->new(<<'BIGN');
32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389437335543602135433229604645318478604952148193555853611059596230698
BIGN

ok($n->is_even($test_n), 'Math::BigInt');

my $b64_n = b64url_encode($n);
is(b64url_decode($b64_n), $n, 'b64url for big numbers');

# https://salmon-protocol.googlecode.com/
#   svn/trunk/lib/python/magicsig_hjfreyer/magicsig_example.py
my $test_key =
    'RSA.'.
    'mVgY8RN6URBTstndvmUUPb4UZTdwvw'.
    'mddSKE5z_jvKUEK6yk1u3rrC9yN8k6'.
    'FilGj9K0eeUPe2hf4Pj-5CmHww==.'.
    'AQAB.'.
    'Lgy_yL3hsLBngkFdDw1Jy9TmSRMiH6'.
    'yihYetQ8jy-jZXdsZXd8V5ub3kuBHH'.
    'k4M39i3TduIkcrjcsiWQb77D8Q==';

my $mkey = Crypt::MagicSignatures::Key->new($test_key);

ok($mkey, 'Magic-Key parsed');                     # 8
ok($mkey->n eq '80312837890751965650228915'.
               '46563591368344944062154100'.
               '50964539889229343337085989'.
               '19433064399074548837475344'.
               '93461257620351548796452092'.
               '307094036643522661681091',
                        'M-Key modulus correct');  # 9
ok($mkey->d eq '24118237980497878083558223'.
               '37426462024816467706597110'.
               '82488260212703094530069868'.
               '86574485408953662105923805'.
               '76050280953899102635751538'.
               '748696981555132000814065',
                        'M-Key private exponent'); # 10
ok($mkey->e == 65537,   'M-Key exponent');         # 11
ok($mkey->_emLen == 64,  'M-Key length correct');   # 12

my $test_public_key = $test_key;
$test_public_key =~ s{\.[^\.]+$}{};

is($mkey->to_string, $test_public_key, 'M-Key string correct'); # 13

my $num = '3799324609234979';
my $b64 = *{"${module}::_hex_to_b64url"}->($num);
is($b64, 'DX93MbhIIw==', '_hex_to_b64url');

my $num2 = *{"${module}::_b64url_to_hex"}->($b64);
is($num, $num2, '_b64url_to_hex');

my $b642 = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.
  'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.
  'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.
  'AAAAAAAAAAAAAAH_____________ADAxMA0GCWC'.
  'GSAFlAwQCAQUABCDVV5xG38x_GCBwE-ZbROTLTi'.
  'wimPSsRXuo-CdD8x6TCw==';
$num2 = *{"${module}::_b64url_to_hex"}->($b642);
my $b643 = *{"${module}::_hex_to_b64url"}->($num2);
my $num3 = *{"${module}::_b64url_to_hex"}->($b643);

is($num2, $num3, '_hex_to_b64url');

$test_msg =    'test string';

my $emsa = *{"${module}::_emsa_encode"}->($test_msg,
					  $mkey->_emLen,
					  'sha-256');

is (b64url_encode($emsa),
    'AAH_____________AD'.
    'AxMA0GCWCGSAFlAwQC'.
    'AQUABCDVV5xG38x_GC'.
    'BwE-ZbROTLTiwimPSs'.
    'RXuo-CdD8x6TCw==',
    'EMSA encode');

my $EM = *{"${module}::_os2ip"}->($emsa);

is($EM, '40917382598701'.
     '77337516485429975'.
     '66029938148046617'.
     '39298138975140811'.
     '97400100914340291'.
     '73326755103708333'.
     '01650201932192494'.
     '82769682303342846'.
     '01470436616606475',
   'EMSA encode os2ip');

my $s  = *{"${module}::_rsasp1"}->($mkey, $EM);

is ($s, '80055379592861'.
      '9970997680410400'.
      '5668460713624089'.
      '8187708914240169'.
      '4631449865271349'.
      '1469283703805848'.
      '8599193791587766'.
      '9585376226384018'.
      '9524960279363800'.
      '402058130813', 'rsasp1 sign');

is(length($mkey->n), 154, 'n length');

my $string = *{"${module}::_i2osp"}->($s, length($mkey->n));

is(length($string), length($mkey->n), '_i2osp for Win32 test');

my $S = b64url_encode($string);

is ($S, 'AAAAAAAAAAAAAAAAAAAAAAAAA'.
        'AAAAAAAAAAAAAAAAAAAAAAAAA'.
	'AAAAAAAAAAAAAAAAAAAAAAAAA'.
	'AAAAAAAAAAAAAAAAAAAAAAAAA'.
	'AAAAAAAAAAAAAAAAAAAA'.
	'mNpBIpTUOESnuQMlS8aWZ4hwd'.
	'SwWnMstrn0F3L9GHDXa238fN3'.
	'Bx3Rl0yvVESM_eZuocLsp9ubU'.
	'rYDu83821fQ==',
    'SIG i2osp b64url_encode');

done_testing;