This is a pure C implementation of polkadot's key derivation and signing algorithm [[https://wiki.polkadot.network/docs/en/learn-cryptography][schnorrkel]]. The goal is to fully compatible with the original [[https://github.com/w3f/schnorrkel][rust version]]. The curve operations are based on [[https://github.com/floodyberry/ed25519-donna][ed25519-donna]]. [[https://github.com/w3f/Grants-Program/blob/master/applications/index.md#%EF%B8%8F-wave-6---q2-2020][file:https://github.com/w3f/Grants-Program/blob/master/static/img/Grants_Program.png?raw=true]]
Compilation ** Default Options
git clone git@github.com: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.
** 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 | 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);
[[https://github.com/TerenceGe/sr25519-donna/blob/954fc1ff50aa919a05b23e28695dc92cab510467/example/src/main.c#L27][example]] ** sign message | 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);
[[https://github.com/TerenceGe/sr25519-donna/blob/954fc1ff50aa919a05b23e28695dc92cab510467/example/src/main.c#L45][example]] ** verify message | 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);
[[https://github.com/TerenceGe/sr25519-donna/blob/954fc1ff50aa919a05b23e28695dc92cab510467/example/src/main.c#L64][example]] ** soft derive keypair | 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);
[[https://github.com/TerenceGe/sr25519-donna/blob/954fc1ff50aa919a05b23e28695dc92cab510467/example/src/main.c#L77][example]] ** soft derive public key | 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);
[[https://github.com/TerenceGe/sr25519-donna/blob/954fc1ff50aa919a05b23e28695dc92cab510467/example/src/main.c#L100][example]] ** hard derive keypair | 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);
[[https://github.com/TerenceGe/sr25519-donna/blob/954fc1ff50aa919a05b23e28695dc92cab510467/example/src/main.c#L118][example]] ** random number generator
void sr25519_randombytes(void *p, size_t len);
** vrf sign | 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);
[[https://github.com/TerenceGe/sr25519-donna/blob/dc22624e80ce1c8fb4df0936678f6edcd8021dfd/example/src/main.c#L155][example]] ** vrf verify | 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);
[[https://github.com/TerenceGe/sr25519-donna/blob/dc22624e80ce1c8fb4df0936678f6edcd8021dfd/example/src/main.c#L169][example]] ** vrf result 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;
** 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. \
| 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);