Peter Jankuliak
Peter Jankuliak

Reputation: 3619

BitTorrent test case failing with libsodium

I'm trying to run the test vector as described in BitTorrent BEP 44 test #1, but I'm not creating the same signature as they do:

305ac8aeb6c9c151fa120f120ea2cfb923564e11552d06a5d856091e5e853cff 1260d3f39e4999684aa92eb73ffd136e6f4f3ecbfda0ce53a1608ecd7ae21f01

Instead, the signature I create using libsodium is:

c44ad65291c2b1087218db8a43e3fa7b73cfa01b585b0ff9e6b962ed50e701a1 6065277417ff5bbae43d9b76e52129d27bf2e33e8b043ea67ace7ff91dae4d02

Using this code:

#include <string.h>
#include <stdio.h>
#include <sodium/crypto_sign.h>

// Test vector #1 from http://bittorrent.org/beps/bep_0044.html
// Using libsodium.
int main(int argc, char *argv[])
{
    const char* buf = "3:seqi1e1:v12:Hello World!";

    const char* sk =
        "\xe0\x6d\x31\x83\xd1\x41\x59\x22\x84\x33\xed\x59\x92\x21\xb8\x0b"
        "\xd0\xa5\xce\x83\x52\xe4\xbd\xf0\x26\x2f\x76\x78\x6e\xf1\xc7\x4d"
        "\xb7\xe7\xa9\xfe\xa2\xc0\xeb\x26\x9d\x61\xe3\xb3\x8e\x45\x0a\x22"
        "\xe7\x54\x94\x1a\xc7\x84\x79\xd6\xc5\x4e\x1f\xaf\x60\x37\x88\x1d";

    unsigned char signature[crypto_sign_BYTES];

    crypto_sign_detached(signature,
            NULL,
            (const unsigned char*) buf,
            strlen(buf),
            (const unsigned char*) sk);

    char signed_buf[crypto_sign_BYTES * 2];

    for (int i = 0; i < sizeof(signature); ++i) {
        sprintf(signed_buf + i*2, "%.2x", signature[i]);
    }

    printf("%s\n", signed_buf);
}

Seems to be something silly I'm missing, but I just can't see it.

Upvotes: 2

Views: 125

Answers (1)

Peter Jankuliak
Peter Jankuliak

Reputation: 3619

As explained here there appear to be (at least) two different formats for private keys. One of them is called ref10 and it is the one used by libsodium. It's composed of 32 bytes of seed concatenated with another 32 bytes of public key.

I couldn't find the name of the other format, but - as also explained in the above link - it's basically the seed hashed with sha512. More precisely

void ref10_to_lib(
        unsigned char *private_key,
        const unsigned char *ref10_private_key)
{
    sha512(ref10_private_key, 32, private_key);
    private_key[0] &= 248;
    private_key[31] &= 63;
    private_key[31] |= 64;
}

The BitTorrent specification uses the second format and to be able to use it, one must use the deprecated crypto_sign_edwards25519sha512batch function instead of crypto_sign_detached as such:

#include <string.h>
#include <stdio.h>
#include <sodium/crypto_sign.h>
#include <sodium/crypto_sign_edwards25519sha512batch.h>

// Test vector #1 from http://bittorrent.org/beps/bep_0044.html
// Using libsodium.
int main(int argc, char *argv[])
{
    const char* buf = "3:seqi1e1:v12:Hello World!";

    const char* sk =
        "\xe0\x6d\x31\x83\xd1\x41\x59\x22\x84\x33\xed\x59\x92\x21\xb8\x0b"
        "\xd0\xa5\xce\x83\x52\xe4\xbd\xf0\x26\x2f\x76\x78\x6e\xf1\xc7\x4d"
        "\xb7\xe7\xa9\xfe\xa2\xc0\xeb\x26\x9d\x61\xe3\xb3\x8e\x45\x0a\x22"
        "\xe7\x54\x94\x1a\xc7\x84\x79\xd6\xc5\x4e\x1f\xaf\x60\x37\x88\x1d";

    unsigned char signature[crypto_sign_BYTES];

    crypto_sign_edwards25519sha512batch(
            signature,
            NULL,
            (const unsigned char*) buf,
            strlen(buf),
            (const unsigned char*) sk);

    char signed_buf[crypto_sign_BYTES * 2];

    for (int i = 0; i < sizeof(signature); ++i) {
        sprintf(signed_buf + i*2, "%.2x", signature[i]);
    }

    printf("%s\n", signed_buf);
}

Upvotes: 2

Related Questions