1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
#include <string.h>
#include <stdlib.h>
#include "ge.h"
#include "curve_sigs.h"
#include "crypto_sign.h"
#include "crypto_additions.h"
int curve25519_sign(unsigned char* signature_out,
const unsigned char* curve25519_privkey,
const unsigned char* msg, const unsigned long msg_len,
const unsigned char* random)
{
ge_p3 ed_pubkey_point; /* Ed25519 pubkey point */
unsigned char ed_pubkey[32]; /* Ed25519 encoded pubkey */
unsigned char *sigbuf; /* working buffer */
unsigned char sign_bit = 0;
if ((sigbuf = malloc(msg_len + 128)) == 0) {
memset(signature_out, 0, 64);
return -1;
}
/* Convert the Curve25519 privkey to an Ed25519 public key */
ge_scalarmult_base(&ed_pubkey_point, curve25519_privkey);
ge_p3_tobytes(ed_pubkey, &ed_pubkey_point);
sign_bit = ed_pubkey[31] & 0x80;
/* Perform an Ed25519 signature with explicit private key */
crypto_sign_modified(sigbuf, msg, msg_len, curve25519_privkey,
ed_pubkey, random);
memmove(signature_out, sigbuf, 64);
/* Encode the sign bit into signature (in unused high bit of S) */
signature_out[63] &= 0x7F; /* bit should be zero already, but just in case */
signature_out[63] |= sign_bit;
free(sigbuf);
return 0;
}
int curve25519_verify(const unsigned char* signature,
const unsigned char* curve25519_pubkey,
const unsigned char* msg, const unsigned long msg_len)
{
fe u;
fe y;
unsigned char ed_pubkey[32];
unsigned char *verifybuf = NULL; /* working buffer */
unsigned char *verifybuf2 = NULL; /* working buffer #2 */
int result;
if ((verifybuf = malloc(msg_len + 64)) == 0) {
result = -1;
goto err;
}
if ((verifybuf2 = malloc(msg_len + 64)) == 0) {
result = -1;
goto err;
}
/* Convert the Curve25519 public key into an Ed25519 public key. In
particular, convert Curve25519's "montgomery" x-coordinate (u) into an
Ed25519 "edwards" y-coordinate:
y = (u - 1) / (u + 1)
NOTE: u=-1 is converted to y=0 since fe_invert is mod-exp
Then move the sign bit into the pubkey from the signature.
*/
fe_frombytes(u, curve25519_pubkey);
fe_montx_to_edy(y, u);
fe_tobytes(ed_pubkey, y);
/* Copy the sign bit, and remove it from signature */
ed_pubkey[31] &= 0x7F; /* bit should be zero already, but just in case */
ed_pubkey[31] |= (signature[63] & 0x80);
memmove(verifybuf, signature, 64);
verifybuf[63] &= 0x7F;
memmove(verifybuf+64, msg, msg_len);
/* Then perform a normal Ed25519 verification, return 0 on success */
/* The below call has a strange API: */
/* verifybuf = R || S || message */
/* verifybuf2 = internal to next call gets a copy of verifybuf, S gets
replaced with pubkey for hashing */
result = crypto_sign_open_modified(verifybuf2, verifybuf, 64 + msg_len, ed_pubkey);
err:
if (verifybuf != NULL) {
free(verifybuf);
}
if (verifybuf2 != NULL) {
free(verifybuf2);
}
return result;
}
|