drm/linux: Improve put_user()
[dragonfly.git] / crypto / openssh / ed25519.c
1 /* $OpenBSD: ed25519.c,v 1.3 2013/12/09 11:03:45 markus Exp $ */
2
3 /*
4  * Public Domain, Authors: Daniel J. Bernstein, Niels Duif, Tanja Lange,
5  * Peter Schwabe, Bo-Yin Yang.
6  * Copied from supercop-20130419/crypto_sign/ed25519/ref/ed25519.c
7  */
8
9 #include "includes.h"
10 #include "crypto_api.h"
11
12 #include "ge25519.h"
13
14 static void get_hram(unsigned char *hram, const unsigned char *sm, const unsigned char *pk, unsigned char *playground, unsigned long long smlen)
15 {
16   unsigned long long i;
17
18   for (i =  0;i < 32;++i)    playground[i] = sm[i];
19   for (i = 32;i < 64;++i)    playground[i] = pk[i-32];
20   for (i = 64;i < smlen;++i) playground[i] = sm[i];
21
22   crypto_hash_sha512(hram,playground,smlen);
23 }
24
25
26 int crypto_sign_ed25519_keypair(
27     unsigned char *pk,
28     unsigned char *sk
29     )
30 {
31   sc25519 scsk;
32   ge25519 gepk;
33   unsigned char extsk[64];
34   int i;
35
36   randombytes(sk, 32);
37   crypto_hash_sha512(extsk, sk, 32);
38   extsk[0] &= 248;
39   extsk[31] &= 127;
40   extsk[31] |= 64;
41
42   sc25519_from32bytes(&scsk,extsk);
43   
44   ge25519_scalarmult_base(&gepk, &scsk);
45   ge25519_pack(pk, &gepk);
46   for(i=0;i<32;i++)
47     sk[32 + i] = pk[i];
48   return 0;
49 }
50
51 int crypto_sign_ed25519(
52     unsigned char *sm,unsigned long long *smlen,
53     const unsigned char *m,unsigned long long mlen,
54     const unsigned char *sk
55     )
56 {
57   sc25519 sck, scs, scsk;
58   ge25519 ger;
59   unsigned char r[32];
60   unsigned char s[32];
61   unsigned char extsk[64];
62   unsigned long long i;
63   unsigned char hmg[crypto_hash_sha512_BYTES];
64   unsigned char hram[crypto_hash_sha512_BYTES];
65
66   crypto_hash_sha512(extsk, sk, 32);
67   extsk[0] &= 248;
68   extsk[31] &= 127;
69   extsk[31] |= 64;
70
71   *smlen = mlen+64;
72   for(i=0;i<mlen;i++)
73     sm[64 + i] = m[i];
74   for(i=0;i<32;i++)
75     sm[32 + i] = extsk[32+i];
76
77   crypto_hash_sha512(hmg, sm+32, mlen+32); /* Generate k as h(extsk[32],...,extsk[63],m) */
78
79   /* Computation of R */
80   sc25519_from64bytes(&sck, hmg);
81   ge25519_scalarmult_base(&ger, &sck);
82   ge25519_pack(r, &ger);
83   
84   /* Computation of s */
85   for(i=0;i<32;i++)
86     sm[i] = r[i];
87
88   get_hram(hram, sm, sk+32, sm, mlen+64);
89
90   sc25519_from64bytes(&scs, hram);
91   sc25519_from32bytes(&scsk, extsk);
92   sc25519_mul(&scs, &scs, &scsk);
93   
94   sc25519_add(&scs, &scs, &sck);
95
96   sc25519_to32bytes(s,&scs); /* cat s */
97   for(i=0;i<32;i++)
98     sm[32 + i] = s[i]; 
99
100   return 0;
101 }
102
103 int crypto_sign_ed25519_open(
104     unsigned char *m,unsigned long long *mlen,
105     const unsigned char *sm,unsigned long long smlen,
106     const unsigned char *pk
107     )
108 {
109   unsigned int i;
110   int ret;
111   unsigned char t2[32];
112   ge25519 get1, get2;
113   sc25519 schram, scs;
114   unsigned char hram[crypto_hash_sha512_BYTES];
115
116   *mlen = (unsigned long long) -1;
117   if (smlen < 64) return -1;
118
119   if (ge25519_unpackneg_vartime(&get1, pk)) return -1;
120
121   get_hram(hram,sm,pk,m,smlen);
122
123   sc25519_from64bytes(&schram, hram);
124
125   sc25519_from32bytes(&scs, sm+32);
126
127   ge25519_double_scalarmult_vartime(&get2, &get1, &schram, &ge25519_base, &scs);
128   ge25519_pack(t2, &get2);
129
130   ret = crypto_verify_32(sm, t2);
131
132   if (!ret)
133   {
134     for(i=0;i<smlen-64;i++)
135       m[i] = sm[i + 64];
136     *mlen = smlen-64;
137   }
138   else
139   {
140     for(i=0;i<smlen-64;i++)
141       m[i] = 0;
142   }
143   return ret;
144 }