Skip to content

Commit

Permalink
Implement adding 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 39d4a8d commit 78ac4f8
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 5 deletions.
77 changes: 74 additions & 3 deletions Secp256k1.xs
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,10 @@ _privkey_negate(self, privkey)
new_seckey[i] = seckey_str[i];
}

int result = secp256k1_ec_seckey_negate(ctx->ctx, new_seckey);
int result = secp256k1_ec_seckey_negate(
ctx->ctx,
new_seckey
);

if (!result) {
croak("resulting negated privkey is not valid");
Expand All @@ -403,14 +406,82 @@ _privkey_negate(self, privkey)
OUTPUT:
RETVAL

SV*
void
_pubkey_negate(self)
SV *self
CODE:
secp256k1_perl *ctx = ctx_from_sv(self);

/* NOTE: result is always 1 */
int result = secp256k1_ec_pubkey_negate(ctx->ctx, ctx->pubkey);
int result = secp256k1_ec_pubkey_negate(
ctx->ctx,
ctx->pubkey
);

SV*
_privkey_add(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("adding 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_add(
ctx->ctx,
new_seckey,
tweak_str
);

if (!result) {
croak("resulting added privkey is 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_add(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("adding a pubkey requires 32-byte tweak");
}

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

if (!result) {
croak("resulting added pubkey is not valid");
}

void
DESTROY(self)
Expand Down
39 changes: 37 additions & 2 deletions lib/Bitcoin/Secp256k1.pm
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,24 @@ sub negate_private_key
{
my ($self, $private_key) = @_;

$private_key = $self->_privkey_negate($private_key);
return $private_key;
return $self->_privkey_negate($private_key);
}

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

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

return $self->_pubkey;
}

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

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

1;
Expand Down Expand Up @@ -281,6 +297,25 @@ Negates a private key and returns it.
Negates a public key and returns it.
=head3 add_private_key
$tweaked = $secp256k1->add_private_key($private_key, $tweak)
Add a C<$tweak> (bytestring of length C<32>) to C<$private_key> (bytestring of
length C<32>). The result is a bytestring containing tweaked private key.
If the arguments or the resulting key are not valid, an exception will be thrown.
=head3 add_public_key
$tweaked = $secp256k1->add_public_key($public_key, $tweak)
Add a C<$tweak> (bytestring of length C<32>) to C<$public_key> (bytestring with
compressed or uncompressed public key). The result is a bytestring containing
tweaked public key in compressed form.
If the arguments or the resulting key are not valid, an exception will be thrown.
=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 @@ -62,5 +62,14 @@ subtest 'should negate' => sub {
is $secp->negate_private_key($t{privkey}), $negated_privkey, 'negated privkey ok';
};

subtest 'should add' => sub {
my $added_pubkey = pack 'H*', '0260213f6d967636c54d8845c23098e0f63d906b7903d23692efa155a155eda169';
my $added_privkey = pack 'H*', '67a239562bcdfa07345b72305eb8567436be572159b3ef64a91d0392388d04bf';
my $tweak = "\x06" x 32;

is $secp->add_public_key($t{pubkey}, $tweak), $added_pubkey, 'added pubkey ok';
is $secp->add_private_key($t{privkey}, $tweak), $added_privkey, 'added privkey ok';
};

done_testing;

0 comments on commit 78ac4f8

Please sign in to comment.