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 }