-
Notifications
You must be signed in to change notification settings - Fork 13
/
ed25519.c
115 lines (94 loc) · 3.27 KB
/
ed25519.c
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
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <ed25519/ed25519.h>
#include <assert.h>
#include <string.h>
#include "ge25519.h"
#include <ed25519/ed25519/crypto_verify.h>
ED25519_EXPORT int ed25519_create_keypair(private_key_t *sk, public_key_t *pk) {
if (!randombytes(sk->data, ed25519_privkey_SIZE))
return ED25519_ERROR; /* RNG failed, not enough entropy */
ed25519_derive_public_key(sk, pk); /* fill with data */
return ED25519_SUCCESS; /* ok */
}
ED25519_EXPORT void ed25519_derive_public_key(const private_key_t *sk, public_key_t *pk) {
unsigned char az[64];
sc25519 scsk;
ge25519 gepk;
sha512(az, sk->data, ed25519_privkey_SIZE);
az[0] &= 248;
az[31] &= 127;
az[31] |= 64;
sc25519_from32bytes(&scsk, az);
ge25519_scalarmult_base(&gepk, &scsk);
ge25519_pack(pk->data, &gepk);
}
ED25519_EXPORT void ed25519_sign(signature_t *sig, const unsigned char *msg,
unsigned long long msglen, const public_key_t *pk,
const private_key_t *sk) {
sha_context ctx;
unsigned char az[64];
unsigned char nonce[64]; // r
unsigned char hram[64];
sc25519 sck, scs, scsk;
ge25519 ger;
sha512_init(&ctx);
sha512_update(&ctx, sk->data, ed25519_privkey_SIZE);
sha512_final(&ctx, az);
az[0] &= 248;
az[31] &= 127;
az[31] |= 64;
/* az: 64-byte H(sk) */
/* az: 32-byte scalar a, 32-byte randomizer z */
sha512_init(&ctx);
sha512_update(&ctx, /* z */ az + 32, 32);
sha512_update(&ctx, msg, msglen);
sha512_final(&ctx, nonce);
/* nonce: 64-byte H(z,msg) */
sc25519_from64bytes(&sck, nonce);
ge25519_scalarmult_base(&ger, &sck);
ge25519_pack(sig->data, &ger);
/* sig: [32 bytes R | 32 bytes uninit] */
sha512_init(&ctx);
// first 32 bytes of signature
sha512_update(&ctx, /* R */ sig->data, 32);
sha512_update(&ctx, /* A */ pk->data, ed25519_pubkey_SIZE);
sha512_update(&ctx, msg, msglen);
sha512_final(&ctx, hram);
/* hram: 64-byte H(R,A,m) */
sc25519_from64bytes(&scs, hram);
sc25519_from32bytes(&scsk, /* a */ az);
sc25519_mul(&scs, &scs, &scsk);
sc25519_add(&scs, &scs, &sck);
/* scs: S = nonce + H(R,A,m)a */
sc25519_to32bytes(sig->data + 32, &scs);
/* sig: [32 bytes R | 32 bytes S] */
}
ED25519_EXPORT int ed25519_verify(const signature_t *sig, const unsigned char *msg,
unsigned long long msglen, const public_key_t *pk) {
sha_context ctx;
unsigned char pkcopy[32];
unsigned char rcopy[32];
unsigned char hram[64];
unsigned char rcheck[32];
ge25519 get1, get2;
sc25519 schram, scs;
if (sig->data[63] & 224) goto badsig;
if (ge25519_unpackneg_vartime(&get1, pk->data)) goto badsig;
memcpy(pkcopy, pk->data, ed25519_pubkey_SIZE);
memcpy(rcopy, /* R, first 32 bytes */ sig->data, 32);
sc25519_from32bytes(&scs, /* S, seconds 32 bytes */ sig->data + 32);
sha512_init(&ctx);
// first 32 bytes of signature
sha512_update(&ctx, /* R */ sig->data, 32);
sha512_update(&ctx, /* A */ pk->data, ed25519_pubkey_SIZE);
sha512_update(&ctx, msg, msglen);
sha512_final(&ctx, hram);
/* scs: S = nonce + H(R,A,m)a */
sc25519_from64bytes(&schram, hram);
ge25519_double_scalarmult_vartime(&get2, &get1, &schram, &scs);
ge25519_pack(rcheck, &get2);
if (crypto_verify_32(rcopy, rcheck) == 0) {
return ED25519_SIGNATURE_VALID;
}
badsig:
return ED25519_SIGNATURE_INVALID;
}