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.
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.
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);
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);
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
./sr25519DonnaTests
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.
#include "sr25519-donna.h"
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];
param | description |
keypair | the output ed25519 compatible keypair, 96 bytes long |
seed | the input mini secret key, 32 bytes long |
void sr25519_keypair_from_seed(sr25519_keypair keypair, const sr25519_mini_secret_key seed);
param | description |
signature | the signature ouput, 64 bytes long |
public_key | the public key of the keypair to sign the message, 32 bytes long |
message and message_length | message 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);
param | description |
signature | the signature bytes to verify, 64 bytes long |
message and message_length | message arrary and length |
public_key | the 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);
param | description |
derived | the derived keypair, 96 bytes long |
keypair | the input keypair, 96 bytes long |
chain_code | the input chain code, 32 bytes long |
void sr25519_derive_keypair_soft(sr25519_keypair derived, const sr25519_keypair keypair, const sr25519_chain_code chain_code);
param | description |
derived_public | the derived public key, 32 bytes long |
public_key | the input public key, 32 bytes long |
chain_code | the 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);
param | description |
derived | the derived keypair, 96 bytes long |
keypair | the input keypair, 96 bytes long |
chain_code | the input chain code, 32 bytes long |
void sr25519_derive_keypair_hard(sr25519_keypair derived, const sr25519_keypair keypair, const sr25519_chain_code chain_code);
void sr25519_randombytes(void *p, size_t len);
param | description |
out_and_proof | output combination of vrf output (32 bytes long) and vrf proof (64 bytes long) |
keypair | keypair 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_length | message arrary and length |
threshold | the 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);
param | description |
public_key | the corresponding public key that signing the message |
message and message_length | message arrary and length |
output | the signature for the message |
proof | the proof of the signature |
threshold | the 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);
The vrf result contains signature result and is_less:
result | the result of the signature currently compatible with the c-binding repo (https://github.com/Warchant/sr25519-crust/blob/2947abb8367d57cd712e8bc80687d224ccd86ccf/src/lib.rs#L31) |
is_less | indicate 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;
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.
param | description |
keypair | the output uniform keypair, 96 bytes long |
seed | the input mini secret key, 32 bytes long |
void sr25519_uniform_keypair_from_seed(sr25519_keypair keypair, const sr25519_mini_secret_key seed);
param | description |
uniform_keypair | the output uniform keypair, 96 bytes long |
ed25519_keypair | the ed25519 compatible keypair, 96 bytes long |
void sr25519_keypair_ed25519_to_uniform(sr25519_keypair uniform_keypair, const sr25519_keypair ed25519_keypair);