Use Ed25519 keys.
[tinc] / src / ed25519 / verify.c
diff --git a/src/ed25519/verify.c b/src/ed25519/verify.c
new file mode 100644 (file)
index 0000000..32f988e
--- /dev/null
@@ -0,0 +1,77 @@
+#include "ed25519.h"
+#include "sha512.h"
+#include "ge.h"
+#include "sc.h"
+
+static int consttime_equal(const unsigned char *x, const unsigned char *y) {
+    unsigned char r = 0;
+
+    r = x[0] ^ y[0];
+    #define F(i) r |= x[i] ^ y[i]
+    F(1);
+    F(2);
+    F(3);
+    F(4);
+    F(5);
+    F(6);
+    F(7);
+    F(8);
+    F(9);
+    F(10);
+    F(11);
+    F(12);
+    F(13);
+    F(14);
+    F(15);
+    F(16);
+    F(17);
+    F(18);
+    F(19);
+    F(20);
+    F(21);
+    F(22);
+    F(23);
+    F(24);
+    F(25);
+    F(26);
+    F(27);
+    F(28);
+    F(29);
+    F(30);
+    F(31);
+    #undef F
+
+    return !r;
+}
+
+int ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key) {
+    unsigned char h[64];
+    unsigned char checker[32];
+    sha512_context hash;
+    ge_p3 A;
+    ge_p2 R;
+
+    if (signature[63] & 224) {
+        return 0;
+    }
+
+    if (ge_frombytes_negate_vartime(&A, public_key) != 0) {
+        return 0;
+    }
+
+    sha512_init(&hash);
+    sha512_update(&hash, signature, 32);
+    sha512_update(&hash, public_key, 32);
+    sha512_update(&hash, message, message_len);
+    sha512_final(&hash, h);
+    
+    sc_reduce(h);
+    ge_double_scalarmult_vartime(&R, h, &A, signature + 32);
+    ge_tobytes(checker, &R);
+
+    if (!consttime_equal(checker, signature)) {
+        return 0;
+    }
+
+    return 1;
+}