summaryrefslogtreecommitdiff
path: root/test/bntests.pl
diff options
context:
space:
mode:
authorRich Salz <rsalz@openssl.org>2016-11-28 12:26:05 -0500
committerRich Salz <rsalz@openssl.org>2016-11-28 12:26:05 -0500
commit8d1ebff41c75e4eebc7d5cc5a561a1bab6b50e70 (patch)
tree7b8ce132ea9c1cf999e72bd67cfe1b4a1a30fbcb /test/bntests.pl
parentb3618f44a7b8504bfb0a64e8a33e6b8e56d4d516 (diff)
downloadopenssl-new-8d1ebff41c75e4eebc7d5cc5a561a1bab6b50e70.tar.gz
Make bntest be (mostly) file-based.
Test suite used from boring, written by David Benjamin. Test driver converted from C++ to C. Added a Perl program to check the testsuite file. Extensive review feedback incorporated (thanks folks). Reviewed-by: Emilia Käsper <emilia@openssl.org> Reviewed-by: Richard Levitte <levitte@openssl.org>
Diffstat (limited to 'test/bntests.pl')
-rwxr-xr-xtest/bntests.pl156
1 files changed, 156 insertions, 0 deletions
diff --git a/test/bntests.pl b/test/bntests.pl
new file mode 100755
index 0000000000..9adeaef177
--- /dev/null
+++ b/test/bntests.pl
@@ -0,0 +1,156 @@
+#! /usr/bin/env perl
+# Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+# Run the tests specified in bntests.txt, as a check against OpenSSL.
+use strict;
+use warnings;
+use Math::BigInt;
+
+my $EXPECTED_FAILURES = 0;
+my $failures = 0;
+
+sub bn
+{
+ my $x = shift;
+ my ($sign, $hex) = ($x =~ /^([+\-]?)(.*)$/);
+
+ $hex = '0x' . $hex if $hex !~ /^0x/;
+ return Math::BigInt->from_hex($sign.$hex);
+}
+
+sub evaluate
+{
+ my $lineno = shift;
+ my %s = @_;
+
+ if ( defined $s{'Sum'} ) {
+ # Sum = A + B
+ my $sum = bn($s{'Sum'});
+ my $a = bn($s{'A'});
+ my $b = bn($s{'B'});
+ return if $sum == $a + $b;
+ } elsif ( defined $s{'LShift1'} ) {
+ # LShift1 = A * 2
+ my $lshift1 = bn($s{'LShift1'});
+ my $a = bn($s{'A'});
+ return if $lshift1 == $a->bmul(2);
+ } elsif ( defined $s{'LShift'} ) {
+ # LShift = A * 2**N
+ my $lshift = bn($s{'LShift'});
+ my $a = bn($s{'A'});
+ my $n = bn($s{'N'});
+ return if $lshift == $a->blsft($n);
+ } elsif ( defined $s{'RShift'} ) {
+ # RShift = A / 2**N
+ my $rshift = bn($s{'RShift'});
+ my $a = bn($s{'A'});
+ my $n = bn($s{'N'});
+ return if $rshift == $a->brsft($n);
+ } elsif ( defined $s{'Square'} ) {
+ # Square = A * A
+ my $square = bn($s{'Square'});
+ my $a = bn($s{'A'});
+ return if $square == $a->bmul($a);
+ } elsif ( defined $s{'Product'} ) {
+ # Product = A * B
+ my $product = bn($s{'Product'});
+ my $a = bn($s{'A'});
+ my $b = bn($s{'B'});
+ return if $product == $a->bmul($b);
+ } elsif ( defined $s{'Quotient'} ) {
+ # Quotient = A / B
+ # Remainder = A - B * Quotient
+ my $quotient = bn($s{'Quotient'});
+ my $remainder = bn($s{'Remainder'});
+ my $a = bn($s{'A'});
+ my $b = bn($s{'B'});
+
+ # First the remainder test.
+ $b->bmul($quotient);
+ my $rempassed = $remainder == $a->bsub($b) ? 1 : 0;
+
+ # Math::BigInt->bdiv() is documented to do floored division,
+ # i.e. 1 / -4 = -1, while OpenSSL BN_div does truncated
+ # division, i.e. 1 / -4 = 0. We need to make the operation
+ # work like OpenSSL's BN_div to be able to verify.
+ $a = bn($s{'A'});
+ $b = bn($s{'B'});
+ my $neg = $a->is_neg() ? !$b->is_neg() : $b->is_neg();
+ $a->babs();
+ $b->babs();
+ $a->bdiv($b);
+ $a->bneg() if $neg;
+ return if $rempassed && $quotient == $a;
+ } elsif ( defined $s{'ModMul'} ) {
+ # ModMul = (A * B) mod M
+ my $modmul = bn($s{'ModMul'});
+ my $a = bn($s{'A'});
+ my $b = bn($s{'B'});
+ my $m = bn($s{'M'});
+ $a->bmul($b);
+ return if $modmul == $a->bmod($m);
+ } elsif ( defined $s{'ModExp'} ) {
+ # ModExp = (A ** E) mod M
+ my $modexp = bn($s{'ModExp'});
+ my $a = bn($s{'A'});
+ my $e = bn($s{'E'});
+ my $m = bn($s{'M'});
+ return if $modexp == $a->bmodpow($e, $m);
+ } elsif ( defined $s{'Exp'} ) {
+ my $exp = bn($s{'Exp'});
+ my $a = bn($s{'A'});
+ my $e = bn($s{'E'});
+ return if $exp == $a ** $e;
+ } elsif ( defined $s{'ModSqrt'} ) {
+ # (ModSqrt * ModSqrt) mod P = A mod P
+ my $modsqrt = bn($s{'ModSqrt'});
+ my $a = bn($s{'A'});
+ my $p = bn($s{'P'});
+ $modsqrt->bmul($modsqrt);
+ $modsqrt->bmod($p);
+ $a->bmod($p);
+ return if $modsqrt == $a;
+ } else {
+ print "# Unknown test: ";
+ }
+ $failures++;
+ print "# #$failures Test (before line $lineno) failed\n";
+ foreach ( keys %s ) {
+ print "$_ = $s{$_}\n";
+ }
+ print "\n";
+}
+
+my $infile = shift || 'bntests.txt';
+die "No such file, $infile" unless -f $infile;
+open my $IN, $infile || die "Can't read $infile, $!\n";
+
+my %stanza = ();
+my $l = 0;
+while ( <$IN> ) {
+ $l++;
+ s|\R$||;
+ next if /^#/;
+ if ( /^$/ ) {
+ if ( keys %stanza ) {
+ evaluate($l, %stanza);
+ %stanza = ();
+ }
+ next;
+ }
+ # Parse 'key = value'
+ if ( ! /\s*([^\s]*)\s*=\s*(.*)\s*/ ) {
+ print "Skipping $_\n";
+ next;
+ }
+ $stanza{$1} = $2;
+};
+evaluate($l, %stanza) if keys %stanza;
+die "Got $failures, expected $EXPECTED_FAILURES"
+ if $infile eq 'bntests.txt' and $failures != $EXPECTED_FAILURES;
+close($IN)