2

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.

Peter Jankuliak
  • 3,464
  • 1
  • 29
  • 40
  • have you checked whether the private key computes to the same pubkey as indicated by the spec? – the8472 Apr 21 '17 at 10:05
  • 1
    I have since found the answer, but haven't had time to answer it here. Apparently there are (at least) two different formats for private keys. The first format is called `ref10` and is used by libsodium. The second format is `ref10` transformed with a one way function as explained [here](https://github.com/orlp/ed25519/issues/10#issuecomment-242761092). If someone beats me to a concise answer with an example using [these functions](https://github.com/jedisct1/libsodium/blob/master/src/libsodium/include/sodium/crypto_sign_edwards25519sha512batch.h) I'll mark it as answer. – Peter Jankuliak Apr 21 '17 at 11:09

1 Answers1

2

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);
}
Peter Jankuliak
  • 3,464
  • 1
  • 29
  • 40