diff options
Diffstat (limited to '3rd_party/ed25519/add_scalar.c')
-rw-r--r-- | 3rd_party/ed25519/add_scalar.c | 69 |
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 @@ | |||
1 | #include "ed25519.h" | ||
2 | #include "ge.h" | ||
3 | #include "sc.h" | ||
4 | #include "sha512.h" | ||
5 | |||
6 | |||
7 | /* see http://crypto.stackexchange.com/a/6215/4697 */ | ||
8 | void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar) { | ||
9 | const unsigned char SC_1[32] = {1}; /* scalar with value 1 */ | ||
10 | |||
11 | unsigned char n[32]; | ||
12 | ge_p3 nB; | ||
13 | ge_p1p1 A_p1p1; | ||
14 | ge_p3 A; | ||
15 | ge_p3 public_key_unpacked; | ||
16 | ge_cached T; | ||
17 | |||
18 | sha512_context hash; | ||
19 | unsigned char hashbuf[64]; | ||
20 | |||
21 | int i; | ||
22 | |||
23 | /* copy the scalar and clear highest bit */ | ||
24 | for (i = 0; i < 31; ++i) { | ||
25 | n[i] = scalar[i]; | ||
26 | } | ||
27 | n[31] = scalar[31] & 127; | ||
28 | |||
29 | /* private key: a = n + t */ | ||
30 | if (private_key) { | ||
31 | sc_muladd(private_key, SC_1, n, private_key); | ||
32 | |||
33 | // https://github.com/orlp/ed25519/issues/3 | ||
34 | sha512_init(&hash); | ||
35 | sha512_update(&hash, private_key + 32, 32); | ||
36 | sha512_update(&hash, scalar, 32); | ||
37 | sha512_final(&hash, hashbuf); | ||
38 | for (i = 0; i < 32; ++i) { | ||
39 | private_key[32 + i] = hashbuf[i]; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | /* public key: A = nB + T */ | ||
44 | if (public_key) { | ||
45 | /* if we know the private key we don't need a point addition, which is faster */ | ||
46 | /* using a "timing attack" you could find out wether or not we know the private | ||
47 | key, but this information seems rather useless - if this is important pass | ||
48 | public_key and private_key seperately in 2 function calls */ | ||
49 | if (private_key) { | ||
50 | ge_scalarmult_base(&A, private_key); | ||
51 | } else { | ||
52 | /* unpack public key into T */ | ||
53 | ge_frombytes_negate_vartime(&public_key_unpacked, public_key); | ||
54 | fe_neg(public_key_unpacked.X, public_key_unpacked.X); /* undo negate */ | ||
55 | fe_neg(public_key_unpacked.T, public_key_unpacked.T); /* undo negate */ | ||
56 | ge_p3_to_cached(&T, &public_key_unpacked); | ||
57 | |||
58 | /* calculate n*B */ | ||
59 | ge_scalarmult_base(&nB, n); | ||
60 | |||
61 | /* A = n*B + T */ | ||
62 | ge_add(&A_p1p1, &nB, &T); | ||
63 | ge_p1p1_to_p3(&A, &A_p1p1); | ||
64 | } | ||
65 | |||
66 | /* pack public key */ | ||
67 | ge_p3_tobytes(public_key, &A); | ||
68 | } | ||
69 | } | ||