package Crypt::PBC::Element;
use strict;
use Carp;
use MIME::Base64;
use Math::BigInt lib => 'GMP';
our %tt; # This maps our element types and our pairings. Arguably this should be
# done in the element references themselves, but those are scalar refs, not
# hash refs.
use overload
'""' => sub { my $this = shift; "Crypt::PBC::Element-$tt{$$this}{t}#$$this" },
'nomethod' => sub { my $this = shift; my $that = pop; croak "arithmetic operation '$that' not defined for $this" };
1;
# DESTROY {{{
sub DESTROY {
my $this = shift;
my $i = $$this;
Crypt::PBC::element_clear( $this );
delete $tt{$i};
}
# }}}
# clone {{{
sub clone {
my $this = shift;
my ($type, $pair) = @{ $tt{$$this} }{qw(t p)};
my $that = eval "\$pair->init_$type";
if( $@ ) {
# Can't call method "init_G1" on an undefined value at (eval 2) line 1.
# at t/13_pow_arith.t line 28
chomp $@; $@ =~ s/at \(eval \d+\) line \d+/during Crypt::PBC::Element::clone()/;
croak $@;
}
return $that->set( $this );
}
*copy = *clone;
# }}}
#### exporters
# as_bytes {{{
sub as_bytes {
my $this = shift;
return Crypt::PBC::export_element( $this );
}
# }}}
# as_hex {{{
sub as_hex {
my $this = shift;
return unpack("H*", $this->as_bytes);
}
*as_str = *as_hex;
# }}}
# as_base64 {{{
sub as_base64 {
my $this = shift;
my $arg = shift || "";
my $that = encode_base64($this->as_bytes, $arg);
$that =~ s/\n$//sg;
return $that;
}
# }}}
# as_bigint {{{
sub as_bigint {
my $this = shift;
my $that = Crypt::PBC::element_to_mpz($this);
my $int = new Math::BigInt;
$int->{value} = $that;
$int->{sign} = '+';
# I wanted to do something like thits, but I think
# the mpz_t's returned from element_to_mpz are always going to be positive...
# $int->{sign} = $this->is_neg ? "-" : "+";
return $int;
}
# }}}
# stddump {{{
sub stddump {
my $this = shift;
Crypt::PBC::element_fprintf(*STDOUT, '%B', $this );
}
# }}}
# errdump {{{
sub errdump {
my $this = shift;
return Crypt::PBC::element_fprintf(*STDERR, '%B', $this );
}
# }}}
#### initializers and set routines
# random {{{
sub random {
my $this = shift;
Crypt::PBC::element_random( $this );
return $this;
}
# }}}
# set_to_bytes {{{
sub set_to_bytes {
my $this = shift;
my $data = shift;
croak "provide something to set the element to" unless defined $data and length $data > 0;
Crypt::PBC::element_from_bytes($this, $data);
$this;
}
# }}}
# set_to_hash {{{
sub set_to_hash {
my $this = shift;
my $hash = shift;
croak "provide something to set the element to" unless defined $hash and length $hash > 0;
#my $type = $tt{$$this}{t};
#warn " >type=$type; hash=$hash...@_...<\n";
Crypt::PBC::element_from_hash($this, $hash);
#warn " <type=$type; hash=$hash...@_...>\n";
$this;
}
# }}}
# set_to_int {{{
sub set_to_int {
my $this = shift;
my $int = shift;
croak "int provided ($int) is not acceptable" unless $int =~ m/^\-?[0-9]+\z/s;
Crypt::PBC::element_set_si($this, $int);
$this;
}
# }}}
# set_to_bigint {{{
sub set_to_bigint {
my $this = shift;
my $int = shift;
croak "int provided is not a bigint" unless ref $int and $int->isa("Math::BigInt");
Crypt::PBC::element_set_mpz($this, $int->{value});
$this;
}
# }}}
# set {{{
sub set {
my $this = shift;
my $that = shift;
croak "LHS and RHS must be algebraically similar ($tt{$$this}{c} vs $tt{$$that}{c})"
unless $tt{$$this}{c} eq $tt{$$that}{c};
Crypt::PBC::element_set($this, $that);
$this;
}
# }}}
# set0 {{{
sub set0 {
my $this = shift;
my $that = shift;
Crypt::PBC::element_set0($this);
$this;
}
# }}}
# set1 {{{
sub set1 {
my $this = shift;
my $that = shift;
Crypt::PBC::element_set1($this);
$this;
}
# }}}
#### comparisons
# is0 {{{
sub is0 {
my $this = shift;
croak "LHS should have a type" unless exists $tt{$$this};
return Crypt::PBC::element_is0( $this );
}
# }}}
# is1 {{{
sub is1 {
my $this = shift;
croak "LHS should have a type" unless exists $tt{$$this};
return Crypt::PBC::element_is1( $this );
}
# }}}
# is_eq {{{
sub is_eq {
my $this = shift;
my $that = shift;
croak "LHS should have a type" unless exists $tt{$$this};
croak "LHS and RHS must be algebraically similar ($tt{$$this}{c} vs $tt{$$that}{c}) "
unless $tt{$$this}{c} eq $tt{$$that}{c};
return not Crypt::PBC::element_cmp( $this, $that ); # returns 0 if they're algebraically similar
}
# }}}
# is_sqr {{{
sub is_sqr {
my $this = shift;
croak "LHS should have a type" unless exists $tt{$$this};
my $type = $tt{$$this}{t};
return 1 if $type eq "G1";
return 1 if $type eq "G2";
return 1 if $type eq "GT";
return Crypt::PBC::element_is_sqr( $this );
}
# }}}
#### exponentiation
# pow_zn {{{
sub pow_zn {
my $this = shift;
my $base = shift;
my $expo = shift;
if( defined $base and not defined $expo ) {
$expo = $base;
$base = $this;
}
croak "LHS should have a type" unless exists $tt{$$this};
croak "LHS and BASE must be algebraically similar ($tt{$$this}{c} vs $tt{$$base}{c})"
unless $tt{$$this}{c} eq $tt{$$base}{c};
croak "EXPO must be of type Zr (not $tt{$$expo}{t})" unless $tt{$$expo}{t} eq "Zr";
Crypt::PBC::element_pow_zn( $this, $base, $expo );
$this;
}
# }}}
# pow2_zn {{{
sub pow2_zn {
my $this = shift;
my $a1 = shift;
my $n1 = shift;
my $a2 = shift;
my $n2 = shift;
croak "LHS should have a type" unless exists $tt{$$this};
croak "LHS and a1 must be algebraically similar ($tt{$$this}{c} vs $tt{$$a1}{c})" unless $tt{$$this}{c} eq $tt{$$a1}{c};
croak "LHS and a2 must be algebraically similar ($tt{$$this}{c} vs $tt{$$a2}{c})" unless $tt{$$this}{c} eq $tt{$$a2}{c};
croak "n1 must be of type Zr (not $tt{$$n1}{t})" unless $tt{$$n1}{t} eq "Zr";
croak "n2 must be of type Zr (not $tt{$$n2}{t})" unless $tt{$$n2}{t} eq "Zr";
Crypt::PBC::element_pow2_zn( $this, $a1, $n1, $a2, $n2 );
$this;
}
# }}}
# pow3_zn {{{
sub pow3_zn {
my $this = shift;
my $a1 = shift;
my $n1 = shift;
my $a2 = shift;
my $n2 = shift;
my $a3 = shift;
my $n3 = shift;
croak "LHS should have a type" unless exists $tt{$$this};
croak "LHS and a1 must be algebraically similar ($tt{$$this}{c} vs $tt{$$a1}{c})" unless $tt{$$this}{c} eq $tt{$$a1}{c};
croak "LHS and a2 must be algebraically similar ($tt{$$this}{c} vs $tt{$$a2}{c})" unless $tt{$$this}{c} eq $tt{$$a2}{c};
croak "LHS and a3 must be algebraically similar ($tt{$$this}{c} vs $tt{$$a3}{c})" unless $tt{$$this}{c} eq $tt{$$a3}{c};
croak "n1 must be of type Zr (not $tt{$$n1}{t})" unless $tt{$$n1}{t} eq "Zr";
croak "n2 must be of type Zr (not $tt{$$n2}{t})" unless $tt{$$n2}{t} eq "Zr";
croak "n3 must be of type Zr (not $tt{$$n3}{t})" unless $tt{$$n3}{t} eq "Zr";
Crypt::PBC::element_pow3_zn( $this, $a1, $n1, $a2, $n2, $a3, $n3 );
$this;
}
# }}}
# pow_bigint {{{
sub pow_bigint {
my $this = shift;
my $base = shift;
my $expo = shift;
if( defined $base and not defined $expo ) {
$expo = $base;
$base = $this;
}
croak "EXPO provided is not a bigint" unless ref $expo and $expo->isa("Math::BigInt");
croak "LHS should have a type" unless exists $tt{$$this};
croak "LHS and BASE must be algebraically similar ($tt{$$this}{c} vs $tt{$$base}{c})"
unless exists $tt{$$this} and $tt{$$this}{c} eq $tt{$$base}{c};
Crypt::PBC::element_pow_mpz( $this, $base, $expo->{value} );
$this;
}
# }}}
# pow2_bigint {{{
sub pow2_bigint {
my $this = shift;
my $a1 = shift;
my $n1 = shift;
my $a2 = shift;
my $n2 = shift;
croak "n1 provided is not a bigint" unless ref $n1 and $n1->isa("Math::BigInt");
croak "n2 provided is not a bigint" unless ref $n2 and $n2->isa("Math::BigInt");
croak "LHS should have a type" unless exists $tt{$$this};
croak "LHS and a1 must be algebraically similar ($tt{$$this}{c} vs $tt{$$a1}{c})" unless $tt{$$this}{c} eq $tt{$$a1}{c};
croak "LHS and a2 must be algebraically similar ($tt{$$this}{c} vs $tt{$$a2}{c})" unless $tt{$$this}{c} eq $tt{$$a2}{c};
Crypt::PBC::element_pow2_mpz( $this, $a1, $n1->{value}, $a2, $n2->{value} );
$this;
}
# }}}
# pow3_bigint {{{
sub pow3_bigint {
my $this = shift;
my $a1 = shift;
my $n1 = shift;
my $a2 = shift;
my $n2 = shift;
my $a3 = shift;
my $n3 = shift;
croak "n1 provided is not a bigint" unless ref $n1 and $n1->isa("Math::BigInt");
croak "n2 provided is not a bigint" unless ref $n2 and $n2->isa("Math::BigInt");
croak "n3 provided is not a bigint" unless ref $n3 and $n2->isa("Math::BigInt");
croak "LHS should have a type" unless exists $tt{$$this};
croak "LHS and a1 must be algebraically similar ($tt{$$this}{c} vs $tt{$$a1}{c})" unless $tt{$$this}{c} eq $tt{$$a1}{c};
croak "LHS and a2 must be algebraically similar ($tt{$$this}{c} vs $tt{$$a2}{c})" unless $tt{$$this}{c} eq $tt{$$a2}{c};
croak "LHS and a3 must be algebraically similar ($tt{$$this}{c} vs $tt{$$a3}{c})" unless $tt{$$this}{c} eq $tt{$$a3}{c};
Crypt::PBC::element_pow3_mpz( $this, $a1, $n1->{value}, $a2, $n2->{value}, $a3, $n3->{value} );
$this;
}
# }}}
#### arith
## 1op
# square {{{
sub square {
my $lhs = shift;
my $rhs = shift;
if( $rhs ) {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS and RHS must be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs}{c})" unless $tt{$$lhs}{c} eq $tt{$$rhs}{c};
} else {
$rhs = $lhs;
}
Crypt::PBC::element_square( $lhs, $rhs );
$lhs;
}
# }}}
# double {{{
sub double {
my $lhs = shift;
my $rhs = shift;
if( $rhs ) {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS and RHS must be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs}{c})" unless $tt{$$lhs}{c} eq $tt{$$rhs}{c};
} else {
$rhs = $lhs;
}
Crypt::PBC::element_double( $lhs, $rhs );
$lhs;
}
# }}}
# halve {{{
sub halve {
my $lhs = shift;
my $rhs = shift;
if( $rhs ) {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS and RHS must be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs}{c})" unless $tt{$$lhs}{c} eq $tt{$$rhs}{c};
} else {
$rhs = $lhs;
}
Crypt::PBC::element_halve( $lhs, $rhs );
$lhs;
}
# }}}
# neg {{{
sub neg {
my $lhs = shift;
my $rhs = shift;
if( $rhs ) {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS and RHS must be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs}{c})" unless $tt{$$lhs}{c} eq $tt{$$rhs}{c};
} else {
$rhs = $lhs;
}
Crypt::PBC::element_neg( $lhs, $rhs );
$lhs;
}
# }}}
# invert {{{
sub invert {
my $lhs = shift;
my $rhs = shift;
if( $rhs ) {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS and RHS must be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs}{c})" unless $tt{$$lhs}{c} eq $tt{$$rhs}{c};
} else {
$rhs = $lhs;
}
Crypt::PBC::element_invert( $lhs, $rhs );
$lhs;
}
# }}}
## 2op
# add {{{
sub add {
my $lhs = shift;
my $rhs1 = shift;
my $rhs2 = shift;
if( $rhs2 ) {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS, RHS1 and RHS2 must be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs1}{c} vs $tt{$$rhs2}{c})"
unless $tt{$$lhs}{c} eq $tt{$$rhs1}{c} and $tt{$$rhs1}{c} eq $tt{$$rhs2}{c};
Crypt::PBC::element_add( $lhs, $rhs1, $rhs2 );
} else {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS and RHS should be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs1}{c})"
unless $tt{$$lhs}{c} eq $tt{$$rhs1}{c};
Crypt::PBC::element_add( $lhs, $lhs, $rhs1 );
}
$lhs;
}
# }}}
# Sub {{{
sub Sub {
my $lhs = shift;
my $rhs1 = shift;
my $rhs2 = shift;
if( $rhs2 ) {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS, RHS1 and RHS2 must be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs1}{c} vs $tt{$$rhs2}{c})"
unless $tt{$$lhs}{c} eq $tt{$$rhs1}{c} and $tt{$$rhs1}{c} eq $tt{$$rhs2}{c};
Crypt::PBC::element_sub( $lhs, $rhs1, $rhs2 );
} else {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS and RHS should be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs1}{c})"
unless $tt{$$lhs}{c} eq $tt{$$rhs1}{c};
Crypt::PBC::element_sub( $lhs, $lhs, $rhs1 );
}
$lhs;
}
# }}}
# mul {{{
sub mul {
my $lhs = shift;
my $rhs1 = shift;
my $rhs2 = shift;
if( $rhs2 ) {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS, RHS1 and RHS2 must be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs1}{c} vs $tt{$$rhs2}{c})"
unless $tt{$$lhs}{c} eq $tt{$$rhs1}{c} and $tt{$$rhs1}{c} eq $tt{$$rhs2}{c};
Crypt::PBC::element_mul( $lhs, $rhs1, $rhs2 );
} else {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS and RHS should be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs1}{c})"
unless $tt{$$lhs}{c} eq $tt{$$rhs1}{c};
Crypt::PBC::element_mul( $lhs, $lhs, $rhs1 );
}
$lhs;
}
# }}}
# div {{{
sub div {
my $lhs = shift;
my $rhs1 = shift;
my $rhs2 = shift;
if( $rhs2 ) {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS, RHS1 and RHS2 must be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs1}{c} vs $tt{$$rhs2}{c})"
unless $tt{$$lhs}{c} eq $tt{$$rhs1}{c} and $tt{$$rhs1}{c} eq $tt{$$rhs2}{c};
Crypt::PBC::element_div( $lhs, $rhs1, $rhs2 );
} else {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS and RHS should be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs1}{c})"
unless $tt{$$lhs}{c} eq $tt{$$rhs1}{c};
Crypt::PBC::element_div( $lhs, $lhs, $rhs1 );
}
$lhs;
}
# }}}
# mul_zn {{{
sub mul_zn {
my $lhs = shift;
my $rhs1 = shift;
my $rhs2 = shift;
if( $rhs2 ) {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS, RHS1 must be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs1}{c})"
unless $tt{$$lhs}{c} eq $tt{$$rhs1}{c};
croak "RHS2 should be in Zr (not $tt{$$rhs2}{t})" unless $tt{$$rhs2}{t} eq "Zr";
Crypt::PBC::element_mul_zn( $lhs, $rhs1, $rhs2 );
} else {
croak "RHS should be in Zr (not $tt{$$rhs1}{t})"
unless $tt{$$rhs1}{t} eq "Zr";
Crypt::PBC::element_mul_zn( $lhs, $lhs, $rhs1 );
}
$lhs;
}
# }}}
# mul_int {{{
sub mul_int {
my $lhs = shift;
my $rhs1 = shift;
my $rhs2 = shift;
if( $rhs2 ) {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS, RHS1 must be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs1}{c})"
unless $tt{$$lhs}{c} eq $tt{$$rhs1}{c};
croak "int provided ($rhs2) is not acceptable" unless $rhs2 =~ m/^\-?[0-9]+\z/s;
Crypt::PBC::element_mul_si( $lhs, $rhs1, $rhs2 );
} else {
croak "int provided ($rhs1) is not acceptable" unless $rhs1 =~ m/^\-?[0-9]+\z/s;
Crypt::PBC::element_mul_si( $lhs, $lhs, $rhs1 );
}
$lhs;
}
# }}}
# mul_bigint {{{
sub mul_bigint {
my $lhs = shift;
my $rhs1 = shift;
my $rhs2 = shift;
if( $rhs2 ) {
croak "LHS should have a type" unless exists $tt{$$lhs};
croak "LHS, RHS1 must be algebraically similar ($tt{$$lhs}{c} vs $tt{$$rhs1}{c})"
unless $tt{$$lhs}{c} eq $tt{$$rhs1}{c};
croak "int provided is not a bigint" unless ref $rhs2 and $rhs2->isa("Math::BigInt");
Crypt::PBC::element_mul_si( $lhs, $rhs1, $rhs2 );
} else {
croak "int provided is not a bigint" unless ref $rhs1 and $rhs1->isa("Math::BigInt");
Crypt::PBC::element_mul_si( $lhs, $lhs, $rhs1 );
}
$lhs;
}
# }}}
# pairing_apply {{{
sub pairing_apply {
my $this = shift;
my $rhs1 = shift;
my $rhs2 = shift;
my $pair = $tt{$$this}{p};
my $c1 = $tt{$$rhs1}{c};
my $c2 = $tt{$$rhs2}{c};
croak "group type for LHS must be GT (not $tt{$$this}{t})" unless $tt{$$this}{t} eq "GT";
croak "group type for RHS1 must be G1 (not $c1)" unless $c1 eq "G1" or $c1 eq "G[12]";
croak "group type for RHS2 must be G2 (not $c2)" unless $c2 eq "G2" or $c2 eq "G[12]";
Crypt::PBC::pairing_apply( $this => ($rhs1, $rhs2) => $pair );
$this;
}
*ehat = *pairing_apply;
*e_hat = *pairing_apply;
*apply_pairing = *pairing_apply;
# }}}
#### package Crypt::PBC::Pairing {{{
package Crypt::PBC::Pairing;
use strict;
use Carp;
1;
sub _stype {
my $this = shift;
my $that = shift;
my $type = shift;
$Crypt::PBC::Element::tt{$$that} = {
t => $type,
p => $this,
c => $type,
};
if( $type =~ m/G[12]/ and Crypt::PBC::pairing_is_symmetric($this) ) {
$Crypt::PBC::Element::tt{$$that}{c} = "G[12]";
}
return;
}
sub init_G1 { my $this = shift; my $that = Crypt::PBC::element_init_G1( $this ); $this->_stype($that => "G1"); $that }
sub init_G2 { my $this = shift; my $that = Crypt::PBC::element_init_G2( $this ); $this->_stype($that => "G2"); $that }
sub init_GT { my $this = shift; my $that = Crypt::PBC::element_init_GT( $this ); $this->_stype($that => "GT"); $that }
sub init_Zr { my $this = shift; my $that = Crypt::PBC::element_init_Zr( $this ); $this->_stype($that => "Zr"); $that }
sub DESTROY { my $this = shift; my $that = Crypt::PBC::pairing_clear( $this ); }
# }}}
#### package Crypt::PBC {{{
package Crypt::PBC;
use strict;
use warnings;
use Carp;
our $VERSION = '0.9000';
# use base 'Exporter';
# our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
# our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
# our @EXPORT = qw( );
#
# sub AUTOLOAD {
# my $constname;
# our $AUTOLOAD; ($constname = $AUTOLOAD) =~ s/.*:://;
# croak "Crypt::PBC::constant wtf($AUTOLOAD, $constname) not defined" if $constname eq 'constant';
# my ($error, $val) = constant($constname);
# if( $error ) { croak $error }
# goto &$AUTOLOAD;
# }
require XSLoader;
XSLoader::load('Crypt::PBC', $VERSION);
1;
sub new {
my $class = shift;
my $that;
my $arg = shift;
TOP: {
if( ref($arg) eq "GLOB" ) {
my $contents = do { local $/; <$arg> };
$arg = $contents;
redo TOP;
} elsif( $arg !~ m/\n/ and -f $arg ) {
open my $in, $arg or croak "couldn't open param file ($arg): $!";
my $contents = do { local $/; <$in> }; close $in;
$arg = $contents;
redo TOP;
} elsif( $arg ) {
$arg =~ s/^\s*//s;
$arg =~ s/\s*$//s;
if( $arg =~ m/^(?s:type\s+[a-z]+\s*|[a-z0-9]+\s+[0-9]+\s*)+\z/s ) {
$that = Crypt::PBC::pairing_init_str($arg);
} else {
croak "either the filename doesn't exist or that param string is unparsable: $arg";
}
} else {
croak "you must pass a file, glob (stream), or init params to new()";
}
}
croak "something went wrong ... you must pass a file, glob (stream), or init params to new()" unless $$that>0;
return $that;
}
# }}}
1;