AtlatestRepositorysigil-crypto
sigil-crypto / tree / nativeed25519.c
1
/*2
* Ed25519 (RFC 8032) and BLAKE2b-512 for (sigil crypto), backed by the3
* vendored Monocypher 4.0.3 (vendor/monocypher, see vendor/MONOCYPHER.md).4
*5
* This file has no platform dependencies: no allocation beyond the result6
* bytevector, no entropy, no clock. It is compiled on every target,7
* including wasm32-wasi, where the Mbed TLS half of the package is not.8
*9
* Natives registered into the (sigil crypto) module:10
*11
* ed25519-verify public-key message signature -> #t | #f12
* ed25519-public-key seed -> bytevector(32)13
* ed25519-sign seed message -> bytevector(64)14
* blake2b-512 data -> bytevector(64)15
*16
* GC discipline: every pointer into a Sigil string or bytevector is used17
* before the single allocation that builds the result, and never after it.18
*/20
#include <sigil/sigil.h>22
#include <string.h>24
#include "monocypher.h"25
#include "monocypher-ed25519.h"27
#include "ed25519.h"29
#define ED25519_KEY_LEN 3230
#define ED25519_SIG_LEN 6431
#define BLAKE2B_512_LEN 6433
static int ed_read_bytes(SigilVM *vm, Value v, const char *what,34
const unsigned char **out_data, size_t *out_len)35
{36
if (sigil_is_string(v)) {37
SigilString *s = (SigilString *)sigil_as_ptr(v);38
*out_data = (const unsigned char *)s->data;39
*out_len = s->byte_length;40
return 1;41
}42
if (sigil_is_bytevector(v)) {43
SigilBytevector *bv = (SigilBytevector *)sigil_as_ptr(v);44
*out_data = bv->data;45
*out_len = bv->length;46
return 1;47
}48
(void)what;49
sigil__vm_error(vm, SIGIL_ERR_TYPE,50
"expected string or bytevector argument");51
return 0;52
}54
static int ed_read_bv_exact(SigilVM *vm, Value v, size_t want,55
const char *type_msg, const char *length_msg,56
const unsigned char **out_data)57
{58
if (!sigil_is_bytevector(v)) {59
sigil__vm_error(vm, SIGIL_ERR_TYPE, type_msg);60
return 0;61
}62
SigilBytevector *bv = (SigilBytevector *)sigil_as_ptr(v);63
if (bv->length != want) {64
sigil__vm_error(vm, SIGIL_ERR_RUNTIME, length_msg);65
return 0;66
}67
*out_data = bv->data;68
return 1;69
}71
static Value ed_make_bytevector(SigilVM *vm, const unsigned char *data,72
size_t len)73
{74
Value result = sigil_make_bytevector(vm, len);75
if (sigil_is_bytevector(result)) {76
memcpy(sigil_bytevector_data(result), data, len);77
}78
return result;79
}81
/*82
* ed25519-verify public-key message signature -> #t | #f83
*84
* public-key: 32-byte bytevector. signature: 64-byte bytevector (R || S).85
* message: string (its UTF-8 bytes) or bytevector. Wrong types or lengths86
* raise; a well-formed signature that does not verify returns #f.87
*/88
static Value native_ed25519_verify(SigilVM *vm, int argc, Value *args)89
{90
(void)argc;91
const unsigned char *pk, *msg, *sig;92
size_t msg_len;93
if (!ed_read_bv_exact(vm, args[0], ED25519_KEY_LEN,94
"ed25519-verify: public key must be a bytevector",95
"ed25519-verify: public key must be 32 bytes", &pk) ||96
!ed_read_bytes(vm, args[1], "message", &msg, &msg_len) ||97
!ed_read_bv_exact(vm, args[2], ED25519_SIG_LEN,98
"ed25519-verify: signature must be a bytevector",99
"ed25519-verify: signature must be 64 bytes", &sig)) {100
return SIGIL_UNDEFINED;101
}102
return sigil_crypto_ed25519_verify(pk, msg, msg_len, sig)103
? SIGIL_TRUE : SIGIL_FALSE;104
}106
/*107
* ed25519-public-key seed -> bytevector(32)108
*109
* seed is the 32-byte RFC 8032 private key. Deterministic, no RNG.110
*/111
static Value native_ed25519_public_key(SigilVM *vm, int argc, Value *args)112
{113
(void)argc;114
const unsigned char *seed_in;115
if (!ed_read_bv_exact(vm, args[0], ED25519_KEY_LEN,116
"ed25519-public-key: seed must be a bytevector",117
"ed25519-public-key: seed must be 32 bytes",118
&seed_in)) {119
return SIGIL_UNDEFINED;120
}121
/* crypto_ed25519_key_pair wipes the seed buffer it is given, so it122
* gets a copy, never the caller's bytevector. */123
unsigned char seed[32], secret[64], pk[32];124
memcpy(seed, seed_in, 32);125
crypto_ed25519_key_pair(secret, pk, seed);126
crypto_wipe(secret, sizeof secret);127
return ed_make_bytevector(vm, pk, sizeof pk);128
}130
/*131
* ed25519-sign seed message -> bytevector(64)132
*133
* Deterministic RFC 8032 signature with the 32-byte seed. Provided because134
* Monocypher implements it alongside verification; sigil-crypto's own use135
* is verification.136
*/137
static Value native_ed25519_sign(SigilVM *vm, int argc, Value *args)138
{139
(void)argc;140
const unsigned char *seed_in, *msg;141
size_t msg_len;142
if (!ed_read_bv_exact(vm, args[0], ED25519_KEY_LEN,143
"ed25519-sign: seed must be a bytevector",144
"ed25519-sign: seed must be 32 bytes", &seed_in) ||145
!ed_read_bytes(vm, args[1], "message", &msg, &msg_len)) {146
return SIGIL_UNDEFINED;147
}148
unsigned char seed[32], secret[64], pk[32], sig[64];149
memcpy(seed, seed_in, 32);150
crypto_ed25519_key_pair(secret, pk, seed);151
crypto_ed25519_sign(sig, secret, msg, msg_len);152
crypto_wipe(secret, sizeof secret);153
/* msg is not touched after this allocation. */154
return ed_make_bytevector(vm, sig, sizeof sig);155
}157
/*158
* blake2b-512 data -> bytevector(64)159
*160
* Unkeyed BLAKE2b with a 64-byte digest (RFC 7693), the hash minisign's161
* prehashed "ED" signatures sign.162
*/163
static Value native_blake2b_512(SigilVM *vm, int argc, Value *args)164
{165
(void)argc;166
const unsigned char *data;167
size_t len;168
if (!ed_read_bytes(vm, args[0], "data", &data, &len)) {169
return SIGIL_UNDEFINED;170
}171
unsigned char hash[BLAKE2B_512_LEN];172
crypto_blake2b(hash, sizeof hash, data, len);173
return ed_make_bytevector(vm, hash, sizeof hash);174
}176
void sigil_crypto_register_ed25519(SigilVM *vm)177
{178
sigil_module_register_native(vm, "ed25519-verify", native_ed25519_verify,179
SIGIL_ARITY_EXACT(3),180
"Verify an Ed25519 (RFC 8032) signature");181
sigil_module_export(vm, "ed25519-verify");182
sigil_module_register_native(vm, "ed25519-public-key",183
native_ed25519_public_key,184
SIGIL_ARITY_EXACT(1),185
"Ed25519 public key from a 32-byte seed");186
sigil_module_export(vm, "ed25519-public-key");187
sigil_module_register_native(vm, "ed25519-sign", native_ed25519_sign,188
SIGIL_ARITY_EXACT(2),189
"Ed25519 (RFC 8032) signature with a 32-byte seed");190
sigil_module_export(vm, "ed25519-sign");191
sigil_module_register_native(vm, "blake2b-512", native_blake2b_512,192
SIGIL_ARITY_EXACT(1),193
"BLAKE2b-512 digest (bytevector)");194
sigil_module_export(vm, "blake2b-512");195
}