1 module sign;
2 
3 extern (C) {
4   int crypto_sign_keypair(ref ubyte[32] pk, ref ubyte[64] sk);
5   int crypto_sign(ubyte *sm, ulong *smlen, ubyte *m, ulong mlen, ref ubyte[64] sk);
6   int crypto_sign_open(ubyte *m, ulong *mlen, ubyte *sm, ulong smlen, ref ubyte[32] pk);
7   size_t crypto_sign_bytes();
8 }
9 
10 struct SignedMessage {
11   ubyte[] data;
12 
13   // signedBy returns true if this messages was signed by the keypair, signer.
14   bool signedBy(SignKeyPair signer) {
15     ubyte[] output = new ubyte[this.data.length - crypto_sign_bytes()];
16     ulong length;
17     int valid = crypto_sign_open(&output[0], &length, &this.data[0], this.data.length, signer.public_key);
18     return (valid == 0);
19   }
20 }
21 
22 class SignKeyPair {
23   ubyte[32] public_key;
24   ubyte[64] secret_key;
25 
26   this() {
27     assert(crypto_sign_keypair(this.public_key, this.secret_key) == 0);
28   }
29 
30   this(ubyte[32] pubk, ubyte[64] secretk) {
31     this.public_key = pubk;
32     this.secret_key = secretk;
33   }
34 
35   SignedMessage sign(string data) {
36     return this.sign(cast(ubyte[])data);
37   }
38 
39   SignedMessage sign(ubyte[] data) {
40     ubyte[] output = new ubyte[data.length + crypto_sign_bytes()];
41     ulong length;
42     assert(crypto_sign(&output[0], &length, &data[0], data.length, this.secret_key) == 0);
43     return SignedMessage(output);
44   }
45 }
46 
47 
48 unittest {
49   auto bob = new SignKeyPair;
50   auto alice = new SignKeyPair;
51 
52   // Test that key signing works
53   SignedMessage data = bob.sign("hey alice this is bob!");
54   assert(data.signedBy(bob));
55   assert(!data.signedBy(alice));
56 }
57