Skip to content

Commit

Permalink
Implement combining public keys
Browse files Browse the repository at this point in the history
  • Loading branch information
bbrtj committed Sep 26, 2024
1 parent e648274 commit 3e51da3
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 22 deletions.
2 changes: 2 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Revision history for Bitcoin-Secp256k1

{{$NEXT}}
[New interface]
- Added method combine_public_keys

0.002 - 2024-09-20
- Module should now be buildable on threaded perls
Expand Down
90 changes: 68 additions & 22 deletions Secp256k1.xs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,31 @@ unsigned char* size_bytestr_from_sv(SV *perlval, size_t wanted_size, char *argna
return bytestr;
}

secp256k1_pubkey* pubkey_from_sv(secp256k1_perl *ctx, SV *data)
{
if (!SvOK(data) || SvROK(data)) {
croak("public key must be defined and not a reference");
}

size_t key_size;
unsigned char *key = bytestr_from_sv(data, &key_size);

secp256k1_pubkey *result_pubkey = malloc(sizeof *result_pubkey);
int result = secp256k1_ec_pubkey_parse(
ctx->ctx,
result_pubkey,
key,
key_size
);

if (!result) {
free(result_pubkey);
croak("the input does not appear to be a valid public key");
}

return result_pubkey;
}

void copy_bytestr(unsigned char *to, unsigned char *from, size_t size)
{
int i;
Expand Down Expand Up @@ -168,28 +193,9 @@ _pubkey(self, ...)
CODE:
secp256k1_perl *ctx = ctx_from_sv(self);
if (items > 1 && SvOK(ST(1))) {
SV *new_pubkey = ST(1);
if (SvROK(new_pubkey)) {
croak("public key must not be a reference");
}

size_t key_size;
unsigned char *key = bytestr_from_sv(new_pubkey, &key_size);

secp256k1_pubkey *result_pubkey = malloc(sizeof *result_pubkey);
int result = secp256k1_ec_pubkey_parse(
ctx->ctx,
result_pubkey,
key,
key_size
);

if (!result) {
free(result_pubkey);
croak("the input does not appear to be a valid public key");
}

secp256k1_perl_replace_pubkey(ctx, result_pubkey);
SV *pubkey_data = ST(1);
secp256k1_pubkey *new_pubkey = pubkey_from_sv(ctx, pubkey_data);
secp256k1_perl_replace_pubkey(ctx, new_pubkey);
}

unsigned int compression = SECP256K1_EC_COMPRESSED;
Expand Down Expand Up @@ -521,6 +527,46 @@ _pubkey_mul(self, tweak)
croak("multiplication arguments are not valid");
}

# Combines public keys together
void
_pubkey_combine(self, ...)
SV *self
CODE:
secp256k1_perl *ctx = ctx_from_sv(self);
int all_keys = items - 1;
if (all_keys == 0) {
croak("need at least one public key to combine");
}

secp256k1_pubkey **keys = malloc(sizeof(keys) * all_keys);
int i;

for (i = 0; i < all_keys; ++i) {
secp256k1_pubkey *new_key = pubkey_from_sv(ctx, ST(i + 1));
keys[i] = new_key;
}

secp256k1_pubkey *result_pubkey = malloc(sizeof *result_pubkey);
int result = secp256k1_ec_pubkey_combine(
ctx->ctx,
result_pubkey,
keys,
all_keys
);

for (i = 0; i < all_keys; ++i) {
free(keys[i]);
}
free(keys);

if (!result) {
free(result_pubkey);
croak("resulting sum of pubkeys is not valid");
}

secp256k1_perl_replace_pubkey(ctx, result_pubkey);


# Destructor
void
DESTROY(self)
Expand Down
17 changes: 17 additions & 0 deletions lib/Bitcoin/Secp256k1.pm
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,15 @@ sub multiply_private_key
return $self->_privkey_mul($private_key, $tweak);
}

sub combine_public_keys
{
my ($self, @public_keys) = @_;

$self->_pubkey_combine(@public_keys);

return $self->_pubkey;
}

1;

__END__
Expand Down Expand Up @@ -345,6 +354,14 @@ Same as L</add_private_key>, but performs multiplication instead of addition.
Same as L</add_public_key>, but performs multiplication instead of addition.
=head3 combine_public_keys
$combined = $secp256k1->combine_public_keys(@pubkeys)
Combines C<@pubkeys> together, returning a new pubkey.
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
10 changes: 10 additions & 0 deletions t/api.t
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,15 @@ subtest 'should multiply' => sub {
is $secp->multiply_private_key($t{privkey}, $tweak), $multiplied_privkey, 'multiplied privkey ok';
};

subtest 'should combine' => sub {
my @to_combine = (
pack('H*', '0311ab47c9252066f0ca5946d70c3aaac1486d65969b90cd57207476963c9f9af3'),
pack('H*', '0260213f6d967636c54d8845c23098e0f63d906b7903d23692efa155a155eda169'),
);
my $combined_pubkey = pack 'H*', '0255c3386d6833d5e1ad6d863afc1cf5d8ffdc0ebc78e4241e845a6c2cbd78157b';

is $secp->combine_public_keys($t{pubkey}, @to_combine), $combined_pubkey, 'combined pubkey ok';
};

done_testing;

0 comments on commit 3e51da3

Please sign in to comment.