1 module wrapper.sodium.crypto_sign_ed25519; 2 3 import wrapper.sodium.core; // assure sodium got initialized 4 5 public 6 import deimos.sodium.crypto_sign_ed25519: crypto_sign_ed25519ph_state, 7 crypto_sign_ed25519ph_statebytes, 8 crypto_sign_ed25519_BYTES, 9 crypto_sign_ed25519_bytes, 10 crypto_sign_ed25519_SEEDBYTES, 11 crypto_sign_ed25519_seedbytes, 12 crypto_sign_ed25519_PUBLICKEYBYTES, 13 crypto_sign_ed25519_publickeybytes, 14 crypto_sign_ed25519_SECRETKEYBYTES, 15 crypto_sign_ed25519_secretkeybytes; 16 /* crypto_sign_ed25519, 17 crypto_sign_ed25519_open, 18 crypto_sign_ed25519_detached, 19 crypto_sign_ed25519_verify_detached, 20 crypto_sign_ed25519_keypair, 21 crypto_sign_ed25519_seed_keypair, 22 crypto_sign_ed25519_pk_to_curve25519, 23 crypto_sign_ed25519_sk_to_curve25519, 24 crypto_sign_ed25519_sk_to_seed, 25 crypto_sign_ed25519_sk_to_pk, 26 crypto_sign_ed25519ph_init, 27 crypto_sign_ed25519ph_update, 28 crypto_sign_ed25519ph_final_create, 29 crypto_sign_ed25519ph_final_verify; */ 30 31 import deimos.sodium.crypto_scalarmult_curve25519 : crypto_scalarmult_curve25519_BYTES; 32 33 import std.exception : assumeWontThrow; 34 import nogc.exception: enforce; 35 36 37 // overloading functions between module deimos.sodium.crypto_sign_ed25519 and this module 38 39 alias crypto_sign_ed25519 = deimos.sodium.crypto_sign_ed25519.crypto_sign_ed25519; 40 41 bool crypto_sign_ed25519(scope ubyte[] sm, 42 scope const ubyte[] m, 43 const ubyte[crypto_sign_ed25519_SECRETKEYBYTES] sk) @nogc @trusted 44 { 45 // enforce(m.length, "Error invoking crypto_sign_ed25519: m is null"); // TODO check if m.ptr==null would be okay 46 const sm_expect_len = m.length + crypto_sign_ed25519_BYTES; 47 // enforce(sm.length == sm_expect_len, "Expected sm.length: ", sm.length, " to be equal to m.length + crypto_sign_ed25519_BYTES: ", sm_expect_len); 48 enforce(sm.length == sm_expect_len, "Expected sm.length is not equal to m.length + crypto_sign_ed25519_BYTES"); 49 ulong smlen_p; 50 bool result = crypto_sign_ed25519(sm.ptr, &smlen_p, m.ptr, m.length, sk.ptr) == 0; // __attribute__ ((nonnull(1, 5))); 51 if (result && smlen_p) 52 assert(smlen_p == sm_expect_len); // okay to be removed in release code 53 return result; 54 } 55 56 alias crypto_sign_ed25519_open = deimos.sodium.crypto_sign_ed25519.crypto_sign_ed25519_open; 57 58 bool crypto_sign_ed25519_open(scope ubyte[] m, 59 scope const ubyte[] sm, 60 const ubyte[crypto_sign_ed25519_PUBLICKEYBYTES] pk) @nogc @trusted // __attribute__ ((warn_unused_result)) 61 { 62 // enforce(sm.length >= crypto_sign_ed25519_BYTES, "Expected sm.length: ", sm.length, " to be greater_equal to crypto_sign_ed25519_BYTES: ", crypto_sign_ed25519_BYTES); 63 enforce(sm.length >= crypto_sign_ed25519_BYTES, "Expected sm.length is not greater_equal to crypto_sign_ed25519_BYTES"); 64 const m_expect_len = sm.length - crypto_sign_ed25519_BYTES; 65 // enforce(m.length == m_expect_len, "Expected m.length: ", m.length, " to be equal to sm.length - crypto_sign_ed25519_BYTES: ", m_expect_len); 66 enforce(m.length == m_expect_len, "Expected m.length is not equal to sm.length - crypto_sign_ed25519_BYTES"); 67 ulong mlen_p; 68 bool result = crypto_sign_ed25519_open(m.ptr, &mlen_p, sm.ptr, sm.length, pk.ptr) == 0; // __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(3, 5))); 69 if (result) 70 assert(mlen_p == sm.length - crypto_sign_ed25519_BYTES); // okay to be removed in release code 71 return result; 72 } 73 74 alias crypto_sign_ed25519_detached = deimos.sodium.crypto_sign_ed25519.crypto_sign_ed25519_detached; 75 76 bool crypto_sign_ed25519_detached(out ubyte[crypto_sign_ed25519_BYTES] sig, 77 scope const ubyte[] m, 78 const ubyte[crypto_sign_ed25519_SECRETKEYBYTES] sk) pure @nogc @trusted 79 { 80 ulong siglen_p; 81 bool result = crypto_sign_ed25519_detached(sig.ptr, &siglen_p, m.ptr, m.length, sk.ptr) == 0; // __attribute__ ((nonnull(1, 5))); 82 if (siglen_p && result) 83 assert(siglen_p == crypto_sign_ed25519_BYTES); 84 return result; 85 } 86 87 alias crypto_sign_ed25519_verify_detached = deimos.sodium.crypto_sign_ed25519.crypto_sign_ed25519_verify_detached; 88 89 pragma(inline, true) 90 bool crypto_sign_ed25519_verify_detached(const ubyte[crypto_sign_ed25519_BYTES] sig, 91 scope const ubyte[] m, 92 const ubyte[crypto_sign_ed25519_PUBLICKEYBYTES] pk) @nogc nothrow pure @trusted // __attribute__ ((warn_unused_result)) 93 { 94 return crypto_sign_ed25519_verify_detached(sig.ptr, m.ptr, m.length, pk.ptr) == 0; // __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4))); 95 } 96 97 98 alias crypto_sign_ed25519_keypair = deimos.sodium.crypto_sign_ed25519.crypto_sign_ed25519_keypair; 99 100 pragma(inline, true) 101 bool crypto_sign_ed25519_keypair(out ubyte[crypto_sign_ed25519_PUBLICKEYBYTES] pk, out ubyte[crypto_sign_ed25519_SECRETKEYBYTES] sk) @nogc nothrow @trusted 102 { 103 return crypto_sign_ed25519_keypair(pk.ptr, sk.ptr) == 0; // __attribute__ ((nonnull)); 104 } 105 106 107 alias crypto_sign_ed25519_seed_keypair = deimos.sodium.crypto_sign_ed25519.crypto_sign_ed25519_seed_keypair; 108 109 pragma(inline, true) 110 bool crypto_sign_ed25519_seed_keypair(out ubyte[crypto_sign_ed25519_PUBLICKEYBYTES] pk, 111 out ubyte[crypto_sign_ed25519_SECRETKEYBYTES] sk, 112 const ubyte[crypto_sign_ed25519_SEEDBYTES] seed) @nogc pure @trusted 113 { 114 return crypto_sign_ed25519_seed_keypair(pk.ptr, sk.ptr, seed.ptr) == 0; // __attribute__ ((nonnull)); 115 } 116 117 alias crypto_sign_ed25519_pk_to_curve25519 = deimos.sodium.crypto_sign_ed25519.crypto_sign_ed25519_pk_to_curve25519; 118 119 pragma(inline, true) 120 bool crypto_sign_ed25519_pk_to_curve25519(out ubyte[crypto_scalarmult_curve25519_BYTES] curve25519_pk, 121 const ubyte[crypto_sign_ed25519_PUBLICKEYBYTES] ed25519_pk) @nogc nothrow pure @trusted // __attribute__ ((warn_unused_result)) 122 { 123 return crypto_sign_ed25519_pk_to_curve25519(curve25519_pk.ptr, ed25519_pk.ptr) == 0; // __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); 124 } 125 126 alias crypto_sign_ed25519_sk_to_curve25519 = deimos.sodium.crypto_sign_ed25519.crypto_sign_ed25519_sk_to_curve25519; 127 128 pragma(inline, true) 129 bool crypto_sign_ed25519_sk_to_curve25519(out ubyte[crypto_scalarmult_curve25519_BYTES] curve25519_sk, 130 const ubyte[crypto_sign_ed25519_SECRETKEYBYTES] ed25519_sk) @nogc pure @trusted 131 { 132 return crypto_sign_ed25519_sk_to_curve25519(curve25519_sk.ptr, ed25519_sk.ptr) == 0; // __attribute__ ((nonnull)); 133 } 134 135 alias crypto_sign_ed25519_sk_to_seed = deimos.sodium.crypto_sign_ed25519.crypto_sign_ed25519_sk_to_seed; 136 137 pragma(inline, true) 138 bool crypto_sign_ed25519_sk_to_seed(out ubyte[crypto_sign_ed25519_SEEDBYTES] seed, 139 const ubyte[crypto_sign_ed25519_SECRETKEYBYTES] sk) @nogc pure @trusted 140 { 141 return crypto_sign_ed25519_sk_to_seed(seed.ptr, sk.ptr) == 0; // __attribute__ ((nonnull)); 142 } 143 144 alias crypto_sign_ed25519_sk_to_pk = deimos.sodium.crypto_sign_ed25519.crypto_sign_ed25519_sk_to_pk; 145 146 pragma(inline, true) 147 bool crypto_sign_ed25519_sk_to_pk(out ubyte[crypto_sign_ed25519_PUBLICKEYBYTES] pk, 148 const ubyte[crypto_sign_ed25519_SECRETKEYBYTES] sk) @nogc pure @trusted 149 { 150 return crypto_sign_ed25519_sk_to_pk(pk.ptr, sk.ptr) == 0; // __attribute__ ((nonnull)); 151 } 152 153 alias crypto_sign_ed25519ph_init = deimos.sodium.crypto_sign_ed25519.crypto_sign_ed25519ph_init; 154 155 pragma(inline, true) 156 bool crypto_sign_ed25519ph_init(ref crypto_sign_ed25519ph_state state) @nogc pure @trusted 157 { 158 return crypto_sign_ed25519ph_init(&state) == 0; // __attribute__ ((nonnull)); 159 } 160 161 alias crypto_sign_ed25519ph_update = deimos.sodium.crypto_sign_ed25519.crypto_sign_ed25519ph_update; 162 163 pragma(inline, true) 164 bool crypto_sign_ed25519ph_update(ref crypto_sign_ed25519ph_state state, 165 scope const ubyte[] m) @nogc pure @trusted 166 { 167 return crypto_sign_ed25519ph_update(&state, m.ptr, m.length) == 0; // __attribute__ ((nonnull(1))); 168 } 169 170 alias crypto_sign_ed25519ph_final_create = deimos.sodium.crypto_sign_ed25519.crypto_sign_ed25519ph_final_create; 171 172 pragma(inline, true) 173 bool crypto_sign_ed25519ph_final_create(ref crypto_sign_ed25519ph_state state, 174 out ubyte[crypto_sign_ed25519_BYTES] sig, 175 const ubyte[crypto_sign_ed25519_SECRETKEYBYTES] sk) @nogc pure @trusted 176 { 177 return crypto_sign_ed25519ph_final_create(&state, sig.ptr, null, sk.ptr) == 0; // __attribute__ ((nonnull(1, 2, 4))); 178 } 179 180 alias crypto_sign_ed25519ph_final_verify = deimos.sodium.crypto_sign_ed25519.crypto_sign_ed25519ph_final_verify; 181 182 pragma(inline, true) 183 bool crypto_sign_ed25519ph_final_verify(ref crypto_sign_ed25519ph_state state, 184 out ubyte[crypto_sign_ed25519_BYTES] sig, 185 const ubyte[crypto_sign_ed25519_PUBLICKEYBYTES] pk) @nogc nothrow pure @trusted 186 { 187 return crypto_sign_ed25519ph_final_verify(&state, sig.ptr, pk.ptr) == 0; // __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); 188 } 189 190 191 @system 192 unittest 193 { 194 import std.stdio : writeln; 195 import std..string : representation; // fromStringz 196 import std.algorithm.comparison : equal; 197 // import std.exception : assertThrown, assertNotThrown; 198 debug writeln("unittest block 1 from sodium.crypto_sign_ed25519.d"); 199 200 auto message = representation("test"); 201 enum message_len = 4; 202 ubyte[crypto_sign_ed25519_PUBLICKEYBYTES] pk = void; 203 ubyte[crypto_sign_ed25519_SECRETKEYBYTES] sk = void; 204 ubyte[crypto_sign_ed25519_SEEDBYTES] seed; 205 assert(crypto_sign_ed25519_seed_keypair(pk.ptr, sk.ptr, seed.ptr) == 0); 206 assert(crypto_sign_ed25519_keypair(pk.ptr, sk.ptr) == 0); // considered impure 207 208 ubyte[crypto_sign_ed25519_BYTES + message_len] signed_message; 209 ulong signed_message_len; 210 crypto_sign_ed25519(signed_message.ptr, &signed_message_len, message.ptr, message.length, sk.ptr); 211 assert(signed_message_len == signed_message.length); 212 213 ubyte[message_len] unsigned_message; 214 ulong unsigned_message_len; 215 assert(crypto_sign_ed25519_open(unsigned_message.ptr, &unsigned_message_len, 216 signed_message.ptr, signed_message_len, pk.ptr) == 0); 217 assert(equal(message[], unsigned_message[])); 218 219 ubyte[crypto_sign_ed25519_BYTES] sig; 220 assert(crypto_sign_ed25519_detached(sig.ptr, null, message.ptr, message_len, sk.ptr) == 0); 221 assert(crypto_sign_ed25519_verify_detached(sig.ptr, message.ptr, message_len, pk.ptr) == 0); 222 223 ubyte[crypto_scalarmult_curve25519_BYTES] curve25519_pk = void; 224 ubyte[crypto_scalarmult_curve25519_BYTES] curve25519_sk = void; 225 crypto_sign_ed25519_pk_to_curve25519(curve25519_pk.ptr, pk.ptr); 226 crypto_sign_ed25519_sk_to_curve25519(curve25519_sk.ptr, sk.ptr); 227 228 auto message_part1 = representation("Arbitrary data to hash"); 229 auto message_part2 = representation("is longer than expected"); 230 crypto_sign_ed25519ph_state state, state_copy; 231 232 /* signature creation */ 233 crypto_sign_ed25519ph_init (&state); 234 crypto_sign_ed25519ph_update(&state, message_part1.ptr, message_part1.length); 235 crypto_sign_ed25519ph_update(&state, message_part2.ptr, message_part2.length); 236 state_copy = state; 237 crypto_sign_ed25519ph_final_create(&state, sig.ptr, null, sk.ptr); 238 /* signature verification */ 239 // crypto_sign_ed25519ph_init (&state); 240 // crypto_sign_ed25519ph_update(&state, message_part1.ptr, message_part1.length); 241 // crypto_sign_ed25519ph_update(&state, message_part2.ptr, message_part2.length); 242 assert(crypto_sign_ed25519ph_final_verify(&state_copy, sig.ptr, pk.ptr) == 0); 243 } 244 245 246 @safe 247 unittest 248 { 249 import std.stdio : writeln; 250 import std..string : representation; // fromStringz 251 import std.algorithm.comparison : equal; 252 import std.exception : assertThrown, assertNotThrown; 253 import wrapper.sodium.randombytes; 254 // import std.range : iota, array; 255 // import std.stdio : writeln, writefln; 256 // import std.algorithm.comparison : equal; 257 // import wrapper.sodium.randombytes : randombytes; 258 debug writeln("unittest block 2 from sodium.crypto_sign_ed25519.d"); 259 260 assert(crypto_sign_ed25519ph_statebytes() == crypto_sign_ed25519ph_state.sizeof); 261 assert(crypto_sign_ed25519_bytes() == crypto_sign_ed25519_BYTES); 262 assert(crypto_sign_ed25519_seedbytes() == crypto_sign_ed25519_SEEDBYTES); 263 assert(crypto_sign_ed25519_publickeybytes() == crypto_sign_ed25519_PUBLICKEYBYTES); 264 assert(crypto_sign_ed25519_secretkeybytes() == crypto_sign_ed25519_SECRETKEYBYTES); 265 266 ubyte[crypto_sign_ed25519_PUBLICKEYBYTES] pk = void; 267 ubyte[crypto_sign_ed25519_SECRETKEYBYTES] sk = void; 268 ubyte[crypto_sign_ed25519_SEEDBYTES] seed = void; 269 randombytes(seed); 270 271 assert(crypto_sign_ed25519_keypair(pk, sk)); 272 assert(crypto_sign_ed25519_seed_keypair(pk, sk, seed)); 273 274 auto message = representation("test"); 275 enum message_len = 4; 276 ubyte[crypto_sign_ed25519_BYTES + message_len] signed_message; 277 assertNotThrown(crypto_sign_ed25519(signed_message[0..$-message_len], null, sk)); 278 assert (crypto_sign_ed25519(signed_message, message, sk)); 279 280 ubyte[message_len] unsigned_message; 281 assertNotThrown(crypto_sign_ed25519_open(unsigned_message, signed_message, pk)); 282 assert(crypto_sign_ed25519_open(unsigned_message, signed_message, pk)); 283 assert(equal(message[], unsigned_message[])); 284 285 ubyte[crypto_sign_ed25519_BYTES] sig; 286 287 assert(crypto_sign_ed25519_detached(sig, message, sk)); 288 assert(crypto_sign_ed25519_verify_detached(sig, message, pk)); 289 290 ubyte[crypto_scalarmult_curve25519_BYTES] curve25519_pk = void; 291 ubyte[crypto_scalarmult_curve25519_BYTES] curve25519_sk = void; 292 crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, pk); 293 crypto_sign_ed25519_sk_to_curve25519(curve25519_sk, sk); 294 295 ubyte[crypto_sign_ed25519_PUBLICKEYBYTES] pk2 = void; 296 ubyte[crypto_sign_ed25519_SEEDBYTES] seed2 = void; 297 298 assert(crypto_sign_ed25519_sk_to_pk(pk2, sk)); 299 assert(equal(pk[], pk2[])); 300 assert(crypto_sign_ed25519_sk_to_seed(seed2, sk)); 301 assert(equal(seed[], seed2[])); 302 303 auto message_part1 = representation("Arbitrary data to hash"); 304 auto message_part2 = representation("is longer than expected"); 305 crypto_sign_ed25519ph_state state, state_copy; 306 307 /* signature creation */ 308 assert(crypto_sign_ed25519ph_init (state)); 309 assert(crypto_sign_ed25519ph_update(state, message_part1)); 310 assert(crypto_sign_ed25519ph_update(state, message_part2)); 311 state_copy = state; 312 assert(crypto_sign_ed25519ph_final_create(state, sig, sk)); 313 314 /* signature verification */ 315 // crypto_sign_ed25519ph_init (state_copy); 316 // crypto_sign_ed25519ph_update(state_copy, message_part1); 317 // crypto_sign_ed25519ph_update(state_copy, message_part2); 318 crypto_sign_ed25519ph_final_verify(state_copy, sig, pk); 319 320 }