Skip to content

Commit

Permalink
Implement multiplying private and public keys
Browse files Browse the repository at this point in the history
  • Loading branch information
bbrtj committed Sep 17, 2024
1 parent 78ac4f8 commit a08d65b
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 0 deletions.
65 changes: 65 additions & 0 deletions Secp256k1.xs
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,71 @@ _pubkey_add(self, tweak)
croak("resulting added pubkey is not valid");
}

SV*
_privkey_mul(self, privkey, tweak)
SV *self
SV *privkey
SV *tweak
CODE:
secp256k1_perl *ctx = ctx_from_sv(self);
size_t seckey_size;
unsigned char *seckey_str = (unsigned char*) SvPVbyte(privkey, seckey_size);

size_t tweak_size;
unsigned char *tweak_str = (unsigned char*) SvPVbyte(tweak, tweak_size);

if (seckey_size != CURVE_SIZE || tweak_size != CURVE_SIZE) {
croak("multiplying a privkey requires 32-byte secret key and tweak");
}

unsigned char new_seckey[CURVE_SIZE];
for (int i = 0; i < CURVE_SIZE; ++i) {
new_seckey[i] = seckey_str[i];
}

int result = secp256k1_ec_seckey_tweak_mul(
ctx->ctx,
new_seckey,
tweak_str
);

if (!result) {
croak("multiplication arguments are not valid");
}

RETVAL = newSVpv((char*) new_seckey, CURVE_SIZE);

/* Clean up the secret, since we copied it to the stack */
for (int i = 0; i < CURVE_SIZE; ++i) {
new_seckey[i] = '\0';
}
OUTPUT:
RETVAL

void
_pubkey_mul(self, tweak)
SV *self
SV *tweak
CODE:
secp256k1_perl *ctx = ctx_from_sv(self);

size_t tweak_size;
unsigned char *tweak_str = (unsigned char*) SvPVbyte(tweak, tweak_size);

if (tweak_size != CURVE_SIZE) {
croak("multiplying a pubkey requires 32-byte tweak");
}

int result = secp256k1_ec_pubkey_tweak_mul(
ctx->ctx,
ctx->pubkey,
tweak_str
);

if (!result) {
croak("multiplication arguments are not valid");
}

void
DESTROY(self)
SV *self
Expand Down
29 changes: 29 additions & 0 deletions lib/Bitcoin/Secp256k1.pm
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,23 @@ sub add_private_key
return $self->_privkey_add($private_key, $tweak);
}

sub multiply_public_key
{
my ($self, $public_key, $tweak) = @_;

$self->_pubkey($public_key);
$self->_pubkey_mul($tweak);

return $self->_pubkey;
}

sub multiply_private_key
{
my ($self, $private_key, $tweak) = @_;

return $self->_privkey_mul($private_key, $tweak);
}

1;

__END__
Expand Down Expand Up @@ -316,6 +333,18 @@ tweaked public key in compressed form.
If the arguments or the resulting key are not valid, an exception will be thrown.
=head3 multiply_private_key
$tweaked = $secp256k1->multiply_private_key($private_key, $tweak)
Same as L</add_private_key>, but performs multiplication instead of addition.
=head3 multiply_public_key
$tweaked = $secp256k1->multiply_public_key($public_key, $tweak)
Same as L</add_public_key>, but performs multiplication instead of addition.
=head1 IMPLEMENTATION
The module consists of two layers:
Expand Down
9 changes: 9 additions & 0 deletions t/api.t
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,14 @@ subtest 'should add' => sub {
is $secp->add_private_key($t{privkey}, $tweak), $added_privkey, 'added privkey ok';
};

subtest 'should multiply' => sub {
my $multiplied_pubkey = pack 'H*', '0311ab47c9252066f0ca5946d70c3aaac1486d65969b90cd57207476963c9f9af3';
my $multiplied_privkey = pack 'H*', '2d40a33515eb26b0fbce29e0e9645e15d6ff4892a17e59ab31b66b496780a683';
my $tweak = "\x06" x 32;

is $secp->multiply_public_key($t{pubkey}, $tweak), $multiplied_pubkey, 'multiplied pubkey ok';
is $secp->multiply_private_key($t{privkey}, $tweak), $multiplied_privkey, 'multiplied privkey ok';
};

done_testing;

0 comments on commit a08d65b

Please sign in to comment.