AtlatestRepositorysigil-crypto

sigil-crypto / tree / nativeed25519.c

1/*
2 * Ed25519 (RFC 8032) and BLAKE2b-512 for (sigil crypto), backed by the
3 * vendored Monocypher 4.0.3 (vendor/monocypher, see vendor/MONOCYPHER.md).
4 *
5 * This file has no platform dependencies: no allocation beyond the result
6 * 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 | #f
12 * 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 used
17 * 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 32
30#define ED25519_SIG_LEN 64
31#define BLAKE2B_512_LEN 64
33static int ed_read_bytes(SigilVM *vm, Value v, const char *what,
34 const unsigned char **out_data, size_t *out_len)
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;
54static 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)
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;
71static Value ed_make_bytevector(SigilVM *vm, const unsigned char *data,
72 size_t len)
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;
81/*
82 * ed25519-verify public-key message signature -> #t | #f
83 *
84 * public-key: 32-byte bytevector. signature: 64-byte bytevector (R || S).
85 * message: string (its UTF-8 bytes) or bytevector. Wrong types or lengths
86 * raise; a well-formed signature that does not verify returns #f.
87 */
88static Value native_ed25519_verify(SigilVM *vm, int argc, Value *args)
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;
106/*
107 * ed25519-public-key seed -> bytevector(32)
108 *
109 * seed is the 32-byte RFC 8032 private key. Deterministic, no RNG.
110 */
111static Value native_ed25519_public_key(SigilVM *vm, int argc, Value *args)
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 it
122 * 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);
130/*
131 * ed25519-sign seed message -> bytevector(64)
132 *
133 * Deterministic RFC 8032 signature with the 32-byte seed. Provided because
134 * Monocypher implements it alongside verification; sigil-crypto's own use
135 * is verification.
136 */
137static Value native_ed25519_sign(SigilVM *vm, int argc, Value *args)
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);
157/*
158 * blake2b-512 data -> bytevector(64)
159 *
160 * Unkeyed BLAKE2b with a 64-byte digest (RFC 7693), the hash minisign's
161 * prehashed "ED" signatures sign.
162 */
163static Value native_blake2b_512(SigilVM *vm, int argc, Value *args)
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);
176void sigil_crypto_register_ed25519(SigilVM *vm)
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");