diff options
Diffstat (limited to 'tests/cryptolib.pl')
-rw-r--r-- | tests/cryptolib.pl | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/tests/cryptolib.pl b/tests/cryptolib.pl new file mode 100644 index 000000000..170a03732 --- /dev/null +++ b/tests/cryptolib.pl @@ -0,0 +1,231 @@ +use Math::BigInt only => 'GMP'; +use Digest::Keccak qw(keccak_256); + +my $p = Math::BigInt->new(2)->bpow(255)->bsub(19); #F_p +my $l = Math::BigInt->new(2)->bpow(252)->badd('27742317777372353535851937790883648493'); +#my $d = Math::BigInt->new(486662); #motgomery: y^2 = x^3 + 486662x^2 + x +my $d = Math::BigInt->new(-121665)->bmul(minv(121666))->bmod($p); #twisted edwards: -x^2 +y^2 = 1 + d*x^2*y^2 +my $x0 = Math::BigInt->new('15112221349535400772501151409588531511454012693041857206046113283949847762202'); +my $y0 = Math::BigInt->new('46316835694926478169428394003475163141307993866256225615783033603165251855960'); #y0 = 4/5 +my $m = Math::BigInt->new('7237005577332262213973186563042994240829374041602535252466099000494570602493'); #p = 8m+5 +my $ps = $p->copy()->bdec->bdiv(4); +my $pl = $p->copy()->bdec->bdiv(2); +my $ii = Math::BigInt->new(2)->bmodpow($ps,$p); #sqrt(-1) + +sub ec_rec { + my $y = Math::BigInt->new($_[0]); + my $xx = $y->copy()->bpow(2)->bdec()->bmul(minv($y->copy()->bpow(2)->bmul($d)->binc))->bmod($p); + return 0 if !($xx->copy()->bmodpow($pl,$p)->binc->bmod($p)); + my $p2 = $p->copy()->badd(3)->bdiv(8); + my $x = $xx->copy()->bmodpow($p2, $p); + if ($x->copy()->bpow(2)->bsub($xx)->bmod($p)) {$x->bmul($ii)->bmod($p)} + if ($x->is_odd) {$x = $p->copy()->bsub($x)}; + return $x; + } + +sub h2i { + return Math::BigInt->new('0x'.(unpack 'H*', (reverse pack 'H*', shift)));; + } + +sub i2h { + my $t = substr(Math::BigInt->new(shift)->as_hex(),2,64); + if (length($t)%2 == 1) {$t = '0'.$t} + return unpack 'H*', (reverse pack 'H*', $t); + } + + +sub random { + return keccak_256(rand(2**20)); + #return keccak_256(3); #I swear that's random! + } + +sub ec_pack { + my $x = Math::BigInt->new($_[0]); + my $y = Math::BigInt->new($_[1]); + my $or = Math::BigInt->new(2)->bpow(255); + $y |= $or if ($x->is_odd()); + return unpack 'H*', (reverse pack 'H*', substr($y->as_hex(),2,64)); + } + +sub ec_unpack { + my $y = Math::BigInt->new(h2i(shift)); + my $b = $y >> 255; + my $and = Math::BigInt->new(2)->bpow(255)->bdec(); + $y &= $and; + my $x = ec_rec($y); + return (0,0) if $x==0; + ($b==0) || ($x = $p->copy()->bsub($x)); + return ($x,$y); + } + + +sub minv { + my $x = Math::BigInt->new(shift); + $x->bmodpow($p-2,$p); + return $x; + } + + +sub ec_doub { + my $x = Math::BigInt->new($_[0]); + my $y = Math::BigInt->new($_[1]); + + #$t = $x->copy()->bpow(2)->bmul(3)->badd($x->copy()->bmul($d)->bmul(2))->binc()->bmul(minv($y->copy()->bmul(2))); #montgomery + #$x2 = $t->copy()->bpow(2)->bsub($d)->bsub($x)->bsub($x)->bmod($p); #montgomery + #$y2 = $x->copy()->bmul(2)->badd($x)->badd($d)->bmul($t)->bsub($t->copy()->bpow(3))->bsub($y)->bmod($p); #montgomery + $t = $x->copy()->bmul($x)->bmul($y)->bmul($y)->bmul($d)->bmod($p); + $x3 = $x->copy()->bmul($y)->bmul(2)->bmul(minv($t+1))->bmod($p); + $y3 = $y->copy()->bpow(2)->badd($x->copy()->bpow(2))->bmul(minv(1-$t))->bmod($p); + return ($x3,$y3); + } +sub ec_add { + my $x1 = Math::BigInt->new($_[0]); + my $y1 = Math::BigInt->new($_[1]); + my $x2 = Math::BigInt->new($_[2]); + my $y2 = Math::BigInt->new($_[3]); + + #$t = $y2->copy()->bsub($y1)->bmul(minv($x2->copy()->bsub($x1))); + #$x3 = $t->copy()->bpow(2)->bsub($d)->bsub($x1)->bsub($x2)->bmod($p); + #$y3 = $x1->copy()->bmul(2)->badd($x2)->badd($d)->bmul($t)->bsub($t->copy()->bpow(3))->bsub($y1)->bmod($p); + $t = $x1->copy->bmul($x2)->bmul($y1)->bmul($y2)->bmul($d)->bmod($p); + $x3 = $x1->copy()->bmul($y2)->badd($y1->copy()->bmul($x2))->bmul(minv($t+1))->bmod($p); + $y3 = $y1->copy()->bmul($y2)->badd($x1->copy()->bmul($x2))->bmul(minv(1-$t))->bmod($p); + + + return ($x3,$y3); + } + +sub ec_mul { + my $n = Math::BigInt->new($_[0]); + my $x = Math::BigInt->new($_[1]); + my $y = Math::BigInt->new($_[2]); + + if ($n->is_one()) { + return ($x,$y); + last; + } + elsif ($n->is_even()) { + $n->bdiv(2); + return ec_mul($n,&ec_doub($x,$y)); + } + else { + $n->bdec()->bdiv(2); + return ec_add($x,$y,ec_mul($n,&ec_doub($x,$y))); + } + } + +sub pkeygen { + my $key = Math::BigInt->new(h2i(shift))->bmod($l); + return ec_pack(ec_mul($key,$x0,$y0)); + } + +sub ec_hash { + my $h = pack 'H*', shift; + my $h = Math::BigInt->new('0x'.(unpack 'H*', reverse keccak_256($h))); + my ($x,$y) = (0,0); + while ($x == 0) { + ($x,$y) = ec_unpack(i2h($h)); + $h->binc(); + } + return ec_mul(8,$x,$y); + } + +sub im_gen { + my ($x,$y) = ec_hash(shift); + my $k = Math::BigInt->new(h2i(shift))->bmod($l); + return ec_pack(ec_mul($k,$x,$y)); + } + + +sub sign { + my ($m,$sec_key) = @_; + my $sec_key = Math::BigInt->new(h2i($sec_key)); + my ($x,$y) = ec_mul($sec_key,$x0,$y0); + my $k = Math::BigInt->new('0x'.(unpack 'H*', random()))->bmod($l); + #my $k = Math::BigInt->new('5267557024171956683337957876581522196748200715787296882078421399301151717969'); + my $e = unpack 'H*', keccak_256($m.(pack 'H*', ec_pack(ec_mul($k,$x0,$y0)))); + my $s = i2h(Math::BigInt->new(h2i($e))->bmul($sec_key)->bneg()->badd($k)->bmod($l)); + $e = i2h(Math::BigInt->new(h2i($e))->bmod($l)); + return ($s,$e); + } + +sub check_s { + my ($m,$pt,$s1,$e1) = @_; + my ($x,$y) = ec_unpack($pt); + my $s = Math::BigInt->new(h2i($s1))->bmod($l); + my $e = Math::BigInt->new(h2i($e1))->bmod($l); + my ($x1,$y1) = ec_add(ec_mul($s,$x0,$y0),ec_mul($e,$x,$y)); + $m = $m.(pack 'H*', ec_pack($x1,$y1)); + my $ev = Math::BigInt->new(h2i(unpack 'H*', keccak_256($m)))->bmod($l); + + return !$ev->bcmp($e); + } + +sub r_sign { + my ($m,$image,$sec_key,$index,@pkeys) = @_; + my ($ix,$iy) = ec_unpack($image); + my $n = @pkeys; + my $data = $m; + my $w = $a = $b = $hx = $hy = $px = $py = 0; + my @zc = (); + my $sum = Math::BigInt->new(); + #print "begin signing ($n keys)\n"; + for $i (0..$n-1) { + ($hx, $hy) = ec_hash(@pkeys[$i]); + ($px,$py) = ec_unpack(@pkeys[$i]); + if ($i == $index) { + $w = Math::BigInt->new('0x'.(unpack 'H*', random()))->bmod($l); + $a = pack 'H*', ec_pack(ec_mul($w,$x0,$y0)); + $b = pack 'H*', ec_pack(ec_mul($w,$hx,$hy)); + push @zc,0,0; + } + else { + $z = Math::BigInt->new('0x'.(unpack 'H*', random()))->bmod($l); + $c = Math::BigInt->new('0x'.(unpack 'H*', random()))->bmod($l); + $sum->badd($c); + $a = pack 'H*', ec_pack(ec_add(ec_mul($z,$x0,$y0),ec_mul($c,$px,$py))); + $b = pack 'H*', ec_pack(ec_add(ec_mul($z,$hx,$hy),ec_mul($c,$ix,$iy))); + push @zc,i2h($z),i2h($c); + } + $data = $data.$a.$b; + #print "key number $i done\n"; + } + #print "generating ringsig..\n"; + my $h = unpack 'H*', keccak_256($data); + my $cy = Math::BigInt->new(h2i($h))->bsub($sum)->bmod($l); + my $zy = $cy->copy()->bmul(h2i($sec_key))->bneg()->badd($w)->bmod($l); + @zc[2*$index] = i2h($zy); + @zc[2*$index+1] = i2h($cy); + return @zc; + } + +sub r_check_s { + my ($m,$image,@zc) = @_; + my $n = @zc/3; + for $j (0..$n-1) { + @pkeys[$j] = shift @zc; + } + my $data = $m; + my ($ix,$iy) = ec_unpack($image); + my $a = $b = $hx = $hy = $px = $py = $z = $c = 0; + my $sum = Math::BigInt->new(); + #print "\nBegin checking ($n keys)\n"; + for $i (0..$n-1) { + $z = Math::BigInt->new(h2i(shift @zc))->bmod($l); + $c = Math::BigInt->new(h2i(shift @zc))->bmod($l); + $sum->badd($c)->bmod($l); + ($px,$py) = ec_unpack(@pkeys[$i]); + $a = pack 'H*', ec_pack(ec_add(ec_mul($z,$x0,$y0),ec_mul($c,$px,$py))); + ($hx, $hy) = ec_hash(@pkeys[$i]); + $b = pack 'H*', ec_pack(ec_add(ec_mul($z,$hx,$hy),ec_mul($c,$ix,$iy))); + $data = $data.$a.$b; + #print "key number $i done\n"; + } + my $h = Math::BigInt->new(h2i(unpack 'H*', keccak_256($data)))->bmod($l); + + return !$h->bcmp($sum); + } + + + + |