123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- #! /usr/bin/env perl
- # Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
- #
- # Licensed under the Apache License 2.0 (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)
|