Coder Social home page Coder Social logo

sr25519-donna's Introduction

sr25519-donna

This is a pure C implementation of polkadot’s key derivation and signing algorithm schnorrkel. The goal is to fully compatible with the original rust version. The curve operations are based on ed25519-donna. https://github.com/w3f/Grants-Program/blob/master/static/img/Grants_Program.png?raw=true

Compilation

Default Options

git clone [email protected]:TerenceGe/sr25519-donna.git
cd sr25519-donna
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=. && make install # The options "-DCMAKE_INSTALL_PREFIX=." will install library in the build folder, you can change the location if you want.

Random Options

This library uses a build-in random number generator by default. To use a custom random function, add -DSR25519_CUSTOMRANDOM=true for cmake

cmake .. -DSR25519_CUSTOMRANDOM=true

put your custom random implementation in sr25519-randombytes-custom.h. The random function must implement:

void sr25519_randombytes(void *p, size_t len);

Hash Options

This library uses a build-in sha2 hash function by default. To use a custom hash function, add -DSR25519_CUSTOMHASH=true for cmake

cmake .. -DSR25519_CUSTOMRANDOM=true

put your custom random implementation in sr25519-hash-custom.h. The random function must implement:

struct sr25519_hash_context;

void sr25519_hash_init(sr25519_hash_context *ctx);
void sr25519_hash_update(sr25519_hash_context *ctx, const uint8_t *in, size_t inlen);
void sr25519_hash_final(sr25519_hash_context *ctx, uint8_t *hash);
void sr25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen);

Curve Operation Options

This library supports both 32bit and 64bit curve operations, the default is according to your machine. Add -DSR25519_FORCE_32BIT to force the use of 32 bit routines even when compiling for 64 bit.

cmake .. -DSR25519_FORCE_32BIT=true

Test

./sr25519DonnaTests

Integration

include_directories(../build/include/) # replace it with your sr25519-donna installed location if required
link_directories(../build/lib/) # replace it with your sr25519-donna installed location if required

add_executable(yourApp ${SOURCE_FILES})
target_link_libraries(yourApp libsr25519_donna.dylib) # replace it with libsr25519_donna_static.a if you want to use static lib.

example

Usage

include

#include "sr25519-donna.h"

sr25519 types

typedef uint8_t sr25519_mini_secret_key[32];
typedef uint8_t sr25519_secret_key[64];
typedef uint8_t sr25519_secret_key_key[32];
typedef uint8_t sr25519_secret_key_nonce[32];
typedef uint8_t sr25519_chain_code[32];
typedef uint8_t sr25519_public_key[32];
typedef uint8_t sr25519_keypair[96];
typedef uint8_t sr25519_signature[64];
typedef uint8_t sr25519_vrf_output[32];
typedef uint8_t sr25519_vrf_io[64];
typedef uint8_t sr25519_vrf_proof[64];
typedef uint8_t sr25519_vrf_out_and_proof[96];
typedef uint8_t sr25519_vrf_proof_batchable[96];
typedef uint8_t sr25519_vrf_raw_output[16];
typedef uint8_t sr25519_vrf_threshold[16];

create keypair from seed

paramdescription
keypairthe output ed25519 compatible keypair, 96 bytes long
seedthe input mini secret key, 32 bytes long
void sr25519_keypair_from_seed(sr25519_keypair keypair, const sr25519_mini_secret_key seed);

example

sign message

paramdescription
signaturethe signature ouput, 64 bytes long
public_keythe public key of the keypair to sign the message, 32 bytes long
message and message_lengthmessage arrary and length
void sr25519_sign(sr25519_signature signature, const sr25519_public_key public_key, const sr25519_secret_key secret, const uint8_t *message, unsigned long message_length);

example

verify message

paramdescription
signaturethe signature bytes to verify, 64 bytes long
message and message_lengthmessage arrary and length
public_keythe corresponding public key that signing the message, 32 bytes long
bool sr25519_verify(const sr25519_signature signature, const uint8_t *message, unsigned long message_length, const sr25519_public_key public_key);

example

soft derive keypair

paramdescription
derivedthe derived keypair, 96 bytes long
keypairthe input keypair, 96 bytes long
chain_codethe input chain code, 32 bytes long
void sr25519_derive_keypair_soft(sr25519_keypair derived, const sr25519_keypair keypair, const sr25519_chain_code chain_code);

example

soft derive public key

paramdescription
derived_publicthe derived public key, 32 bytes long
public_keythe input public key, 32 bytes long
chain_codethe input chain code, 32 bytes long
void sr25519_derive_public_soft(sr25519_public_key derived_public, const sr25519_public_key public_key, const sr25519_chain_code chain_code);

example

hard derive keypair

paramdescription
derivedthe derived keypair, 96 bytes long
keypairthe input keypair, 96 bytes long
chain_codethe input chain code, 32 bytes long
void sr25519_derive_keypair_hard(sr25519_keypair derived, const sr25519_keypair keypair, const sr25519_chain_code chain_code);

example

random number generator

void sr25519_randombytes(void *p, size_t len);

vrf sign

paramdescription
out_and_proofoutput combination of vrf output (32 bytes long) and vrf proof (64 bytes long)
keypairkeypair for signing, it should be an uniform keypair instead of ed25519 compatible, you can generated by sr25519_uniform_keypair_from_seed or converted by sr25519_keypair_ed25519_to_uniform
message and message_lengthmessage arrary and length
thresholdthe vrf threshold, 16 bytes long, if the raw output bytes is less than threshold, the is_less field of result strcut will be true
VrfResult sr25519_vrf_sign_if_less(sr25519_vrf_out_and_proof out_and_proof, const sr25519_keypair keypair, const uint8_t *message, unsigned long message_length, const sr25519_vrf_threshold limit);

example

vrf verify

paramdescription
public_keythe corresponding public key that signing the message
message and message_lengthmessage arrary and length
outputthe signature for the message
proofthe proof of the signature
thresholdthe vrf threshold, 16 bytes long, if the raw output bytes is less than threshold, the is_less field of result structure will be true. If errors, is_less field of the returned structure is not meant to contain a valid value
VrfResult sr25519_vrf_verify(const sr25519_public_key public_key, const uint8_t *message, unsigned long message_length, const sr25519_vrf_output output, const sr25519_vrf_proof proof, const sr25519_vrf_threshold threshold);

example

vrf result

The vrf result contains signature result and is_less:

resultthe result of the signature currently compatible with the c-binding repo (https://github.com/Warchant/sr25519-crust/blob/2947abb8367d57cd712e8bc80687d224ccd86ccf/src/lib.rs#L31)
is_lessindicate whether the raw output bytes is less than the threshold
typedef enum Sr25519SignatureResult {
    Ok,
    EquationFalse,
    PointDecompressionError,
    ScalarFormatError,
    BytesLengthError,
    NotMarkedSchnorrkel,
    MuSigAbsent,
    MuSigInconsistent,
} Sr25519SignatureResult;

typedef struct VrfResult {
    Sr25519SignatureResult result;
    bool is_less;
} VrfResult;

vrf keypair

By default, the sr25519_keypair_from_seed functon creates keypair that contains half ed25519 bytes (which is compatible with the wasm crypto lib), vrf requires the keypair is uniform. In this case, you can use sr25519_uniform_keypair_from_seed for keypair creating or sr25519_keypair_ed25519_to_uniform for converting.

paramdescription
keypairthe output uniform keypair, 96 bytes long
seedthe input mini secret key, 32 bytes long
void sr25519_uniform_keypair_from_seed(sr25519_keypair keypair, const sr25519_mini_secret_key seed);
paramdescription
uniform_keypairthe output uniform keypair, 96 bytes long
ed25519_keypairthe ed25519 compatible keypair, 96 bytes long
void sr25519_keypair_ed25519_to_uniform(sr25519_keypair uniform_keypair, const sr25519_keypair ed25519_keypair);

example

Author

Terence Ge

License

Apache License

sr25519-donna's People

Contributors

terencege avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

sr25519-donna's Issues

Security

Hello! Thank you for such useful implementation. I have several questions:

  1. Is there any security audit conducted for the library as part of the w3f grant?

  2. Looks like in sr25519_keypair_ed25519_to_uniform implementation missing secret_key_key[31] &= 0b0111_1111 operation. As I understand it protects against invalid value which still have nonzero probability. Am I missing something?

Can link with libsodium in same project?

Hi, thanks for this project, it looks great.

I am trying to link against my project which is already using libsodium. However, I'm getting many multiple reference errors in the linker:

$ make
clang -o substrate_test src/utils/ss58.o src/utils/crypto.o src/address.o -Wall --static -fPIC -Isrc -Ilibs/deps/include -Llibs/deps -Llibs/deps/lib -lbase58 -lfastpbkdf2 -lsr25519_donna_static -lsodium -lbc-bip39 -lbc-crypto-base  -lssl -lcrypto -pthread
/mnt/c/Users/matth/Desktop/polkadot/libs/libsodium-stable/src/libsodium/sodium/core.c:188: multiple definition of `sodium_misuse'; libs/deps/lib/libsr25519_donna_static.a(core.c.o):core.c:(.text+0x20): first defined here
/usr/bin/ld: libs/deps/lib/libsodium.a(libsodium_la-ed25519_ref10.o): in function `ge25519_scalarmult':
/mnt/c/Users/matth/Desktop/polkadot/libs/libsodium-stable/src/libsodium/crypto_core/ed25519/ref10/ed25519_ref10.c:813: multiple definition of `ge25519_scalarmult'; libs/deps/lib/libsr25519_donna_static.a(ristretto255.c.o):ristretto255.c:(.text+0xe7e0): first defined here

And it continues with some other functions that have been redefined.

Generated keypair doesn't match that of @polkadot/util-crypto

Any ideas why?

Here's my code:

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "sr25519-donna.h"

#define FROMHEX_MAXLEN 512

uint8_t uchar_ct_eq(const unsigned char a, const unsigned char b) {
    unsigned char x = ~(a ^ b);

    x &= x >> 4;
    x &= x >> 2;
    x &= x >> 1;

    return (uint8_t)x;
}

uint8_t uint8_32_ct_eq(const unsigned char a[32], const unsigned char b[32]) {
    unsigned char x = 1;
    unsigned char i;

    for (i=0; i<32; i++) {
        x &= uchar_ct_eq(a[i], b[i]);
    }

    return (uint8_t)x;
}

uint8_t uint8_64_ct_eq(const unsigned char a[64], const unsigned char b[64]) {
    unsigned char x = 1;
    unsigned char i;

    for (i=0; i<64; i++) {
        x &= uchar_ct_eq(a[i], b[i]);
    }

    return (uint8_t)x;
}

const uint8_t *fromhex(const char *str) {
  static uint8_t buf[FROMHEX_MAXLEN];
  size_t len = strlen(str) / 2;
  if (len > FROMHEX_MAXLEN) len = FROMHEX_MAXLEN;
  for (size_t i = 0; i < len; i++) {
    uint8_t c = 0;
    if (str[i * 2] >= '0' && str[i * 2] <= '9') c += (str[i * 2] - '0') << 4;
    if ((str[i * 2] & ~0x20) >= 'A' && (str[i * 2] & ~0x20) <= 'F')
      c += (10 + (str[i * 2] & ~0x20) - 'A') << 4;
    if (str[i * 2 + 1] >= '0' && str[i * 2 + 1] <= '9')
      c += (str[i * 2 + 1] - '0');
    if ((str[i * 2 + 1] & ~0x20) >= 'A' && (str[i * 2 + 1] & ~0x20) <= 'F')
      c += (10 + (str[i * 2 + 1] & ~0x20) - 'A');
    buf[i] = c;
  }
  return buf;
}

void printHex(const uint8_t *data, size_t len) {
  for (size_t i = 0; i < len; i++) {
    printf("%02x", data[i]);
  }
}

void creates_pair_from_known_seed() {
    printf("test creates pair from known seed: ");

    sr25519_mini_secret_key seed = {0};
    memcpy(seed, fromhex("42f2524bd7800cc244deb8ce5b4c24cb262c1ba317b86880d7ff33f1e93c6348"), 32);


    sr25519_keypair keypair = {0};
    sr25519_keypair_from_seed(keypair, seed);
    
    sr25519_public_key expected_public = {0};
    memcpy(expected_public, fromhex("6a7636545fecfa16f2e37679ea8547685cc2149807f94a4ada6ec0a264ead14d"), 32);
    
    sr25519_public_key public_key = {0};
    memcpy(public_key, keypair + 64, 32);

    sr25519_secret_key private = {0};
    memcpy(private, keypair, 64);

    sr25519_secret_key expected_private = {0};
    memcpy(expected_private, fromhex("a8e59c0eaa54b586bafabe3e4c5597d6b96677c61105e60b0f690327f8d4db4fc7f7331ec0a5bd07390edee454c6e60508af900be8b8682da35b94420992f460"), 32);

    if (!uint8_32_ct_eq(public_key, expected_public) || !uint8_64_ct_eq(private, expected_private)) {
        printf("failed!\n");
        printf("public: ");
        printHex(public_key, 32);
        printf("\n");
        printf("private: ");
        printHex(private, 64);
        printf("\n");
    } else {
        printf("success!\n");
    }
}

int main(int argc, char *argv[]) {
    creates_pair_from_known_seed();

    return 0;
}

and

const { sr25519PairFromSeed, cryptoWaitReady } = require('@polkadot/util-crypto')

cryptoWaitReady().then(() => {
    const pair = sr25519PairFromSeed(Buffer.from("42f2524bd7800cc244deb8ce5b4c24cb262c1ba317b86880d7ff33f1e93c6348", 'hex'))

    console.log(Buffer.from(pair.publicKey).toString('hex'))
    console.log(Buffer.from(pair.secretKey).toString('hex'))
})

Trouble including sr25519 in C++ project due to "public" reserved word

In file included from libs/deps/include/sr25519-donna.h:5:
libs/deps/include/sr25519.h:66:73: error: invalid parameter name: 'public' is a keyword
void sr25519_sign(sr25519_signature signature, const sr25519_public_key public, const sr25519_secret_key secret, const uint8_t *message, unsigned long message_length);
                                                                        ^
libs/deps/include/sr25519.h:73:135: error: invalid parameter name: 'public' is a keyword
bool sr25519_verify(const sr25519_signature signature, const uint8_t *message, unsigned long message_length, const sr25519_public_key public);
                                                                                                                                      ^
libs/deps/include/sr25519.h:87:93: error: invalid parameter name: 'public' is a keyword
void sr25519_derive_public_soft(sr25519_public_key derived_public, const sr25519_public_key public, const sr25519_chain_code chain_code);
                                                                                            ^
libs/deps/include/sr25519.h:112:55: error: invalid parameter name: 'public' is a keyword
VrfResult sr25519_vrf_verify(const sr25519_public_key public, const uint8_t *message, unsigned long message_length, const sr25519_vrf_output output, const sr25519_vrf_proof proof, const sr25519_vrf_threshold threshold);

Using clang++

Generate address from mnemonic phrase

Hi my friend

Thank you for your code
I want to generate an address from a mnemonic like "unveil town glide evil true churn warfare banner agent onion uncle process".
Please Help,

Thanks,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.