summaryrefslogtreecommitdiffstats
path: root/3rd_party/ed25519/add_scalar.c
diff options
context:
space:
mode:
Diffstat (limited to '3rd_party/ed25519/add_scalar.c')
-rw-r--r--3rd_party/ed25519/add_scalar.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/3rd_party/ed25519/add_scalar.c b/3rd_party/ed25519/add_scalar.c
new file mode 100644
index 0000000..7528a7a
--- /dev/null
+++ b/3rd_party/ed25519/add_scalar.c
@@ -0,0 +1,69 @@
+#include "ed25519.h"
+#include "ge.h"
+#include "sc.h"
+#include "sha512.h"
+
+
+/* see http://crypto.stackexchange.com/a/6215/4697 */
+void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar) {
+ const unsigned char SC_1[32] = {1}; /* scalar with value 1 */
+
+ unsigned char n[32];
+ ge_p3 nB;
+ ge_p1p1 A_p1p1;
+ ge_p3 A;
+ ge_p3 public_key_unpacked;
+ ge_cached T;
+
+ sha512_context hash;
+ unsigned char hashbuf[64];
+
+ int i;
+
+ /* copy the scalar and clear highest bit */
+ for (i = 0; i < 31; ++i) {
+ n[i] = scalar[i];
+ }
+ n[31] = scalar[31] & 127;
+
+ /* private key: a = n + t */
+ if (private_key) {
+ sc_muladd(private_key, SC_1, n, private_key);
+
+ // https://github.com/orlp/ed25519/issues/3
+ sha512_init(&hash);
+ sha512_update(&hash, private_key + 32, 32);
+ sha512_update(&hash, scalar, 32);
+ sha512_final(&hash, hashbuf);
+ for (i = 0; i < 32; ++i) {
+ private_key[32 + i] = hashbuf[i];
+ }
+ }
+
+ /* public key: A = nB + T */
+ if (public_key) {
+ /* if we know the private key we don't need a point addition, which is faster */
+ /* using a "timing attack" you could find out wether or not we know the private
+ key, but this information seems rather useless - if this is important pass
+ public_key and private_key seperately in 2 function calls */
+ if (private_key) {
+ ge_scalarmult_base(&A, private_key);
+ } else {
+ /* unpack public key into T */
+ ge_frombytes_negate_vartime(&public_key_unpacked, public_key);
+ fe_neg(public_key_unpacked.X, public_key_unpacked.X); /* undo negate */
+ fe_neg(public_key_unpacked.T, public_key_unpacked.T); /* undo negate */
+ ge_p3_to_cached(&T, &public_key_unpacked);
+
+ /* calculate n*B */
+ ge_scalarmult_base(&nB, n);
+
+ /* A = n*B + T */
+ ge_add(&A_p1p1, &nB, &T);
+ ge_p1p1_to_p3(&A, &A_p1p1);
+ }
+
+ /* pack public key */
+ ge_p3_tobytes(public_key, &A);
+ }
+}