v / vlib / crypto / ed25519 / ed25519.v
181 lines · 140 sloc · 4.93 KB · 008aaad99981918c51194d7aaaaaccb4c258f244
Raw
1module ed25519
2
3import crypto.rand
4import crypto.sha512
5import crypto.internal.subtle
6import crypto.ed25519.internal.edwards25519
7
8// public_key_size is the sizeof public keys in bytes
9pub const public_key_size = 32
10
11// private_key_size is the sizeof private keys in bytes
12pub const private_key_size = 64
13
14// signature_size is the size of signatures generated and verified by this modules, in bytes.
15pub const signature_size = 64
16
17// seed_size is the size of private key seeds in bytes
18pub const seed_size = 32
19
20// `PublicKey` is Ed25519 public keys.
21pub type PublicKey = []u8
22
23// equal reports whether p and x have the same value.
24pub fn (p PublicKey) equal(x []u8) bool {
25 return subtle.constant_time_compare(p, PublicKey(x)) == 1
26}
27
28// PrivateKey is Ed25519 private keys
29pub type PrivateKey = []u8
30
31// seed returns the private key seed corresponding to priv.
32// RFC 8032's private keys correspond to seeds in this module.
33pub fn (priv PrivateKey) seed() []u8 {
34 mut seed := []u8{len: seed_size}
35 copy(mut seed, priv[..32])
36 return seed
37}
38
39// public_key returns the []u8 corresponding to priv.
40pub fn (priv PrivateKey) public_key() PublicKey {
41 assert priv.len == private_key_size
42 mut publickey := []u8{len: public_key_size}
43 copy(mut publickey, priv[32..])
44 return PublicKey(publickey)
45}
46
47// currentyly x not `crypto.PrivateKey`
48pub fn (priv PrivateKey) equal(x []u8) bool {
49 return subtle.constant_time_compare(priv, PrivateKey(x)) == 1
50}
51
52// sign signs the given message with priv.
53pub fn (priv PrivateKey) sign(message []u8) ![]u8 {
54 /*
55 if opts.HashFunc() != crypto.Hash(0) {
56 return nil, errors.New("ed25519: cannot sign hashed message")
57 }*/
58
59 return sign(priv, message)
60}
61
62// sign`signs the message with privatekey and returns a signature
63pub fn sign(privatekey PrivateKey, message []u8) ![]u8 {
64 mut signature := []u8{len: signature_size}
65 sign_generic(mut signature, privatekey, message)!
66 return signature
67}
68
69fn sign_generic(mut signature []u8, privatekey []u8, message []u8) ! {
70 if privatekey.len != private_key_size {
71 panic('ed25519: bad private key length: ${privatekey.len}')
72 }
73 seed, publickey := privatekey[..seed_size], privatekey[seed_size..]
74
75 mut h := sha512.sum512(seed)
76 mut s := edwards25519.new_scalar()
77 s.set_bytes_with_clamping(h[..32])!
78 mut prefix := unsafe { h[32..] }
79
80 mut mh := sha512.new()
81 mh.write(prefix)!
82 mh.write(message)!
83
84 mut msg_digest := []u8{cap: sha512.size}
85 msg_digest = mh.sum(msg_digest)
86
87 mut r := edwards25519.new_scalar()
88 r.set_uniform_bytes(msg_digest)!
89
90 mut rr := edwards25519.Point{}
91 rr.scalar_base_mult(mut r)
92
93 mut kh := sha512.new()
94 kh.write(rr.bytes())!
95 kh.write(publickey)!
96 kh.write(message)!
97
98 mut hram_digest := []u8{cap: sha512.size}
99 hram_digest = kh.sum(hram_digest)
100 mut k := edwards25519.new_scalar()
101 k.set_uniform_bytes(hram_digest)!
102
103 mut ss := edwards25519.new_scalar()
104 ss.multiply_add(k, s, r)
105
106 copy(mut signature[..32], rr.bytes())
107 copy(mut signature[32..], ss.bytes())
108}
109
110// verify reports whether sig is a valid signature of message by publickey.
111pub fn verify(publickey PublicKey, message []u8, sig []u8) !bool {
112 if publickey.len != public_key_size {
113 return error('ed25519: bad public key length: ${publickey.len}')
114 }
115
116 if sig.len != signature_size || sig[63] & 224 != 0 {
117 return false
118 }
119
120 mut aa := edwards25519.Point{}
121 aa.set_bytes(publickey)!
122
123 mut kh := sha512.new()
124 kh.write(sig[..32])!
125 kh.write(publickey)!
126 kh.write(message)!
127
128 mut hram_digest := []u8{cap: sha512.size}
129 hram_digest = kh.sum(hram_digest)
130
131 mut k := edwards25519.new_scalar()
132 k.set_uniform_bytes(hram_digest)!
133
134 mut ss := edwards25519.new_scalar()
135 ss.set_canonical_bytes(sig[32..])!
136
137 // [S]B = R + [k]A --> [k](-A) + [S]B = R
138 mut minus_a := edwards25519.Point{}
139 minus_a.negate(aa)
140 mut rr := edwards25519.Point{}
141 rr.vartime_double_scalar_base_mult(k, minus_a, ss)
142
143 return subtle.constant_time_compare(sig[..32], rr.bytes()) == 1
144}
145
146// generate_key generates a public/private key pair entropy using `crypto.rand`.
147pub fn generate_key() !(PublicKey, PrivateKey) {
148 mut seed := rand.bytes(seed_size)!
149
150 privatekey := new_key_from_seed(seed)
151 mut publickey := []u8{len: public_key_size}
152 copy(mut publickey, privatekey[32..])
153
154 return publickey, privatekey
155}
156
157// new_key_from_seed calculates a private key from a seed. private keys of RFC 8032
158// correspond to seeds in this module
159pub fn new_key_from_seed(seed []u8) PrivateKey {
160 // Outline the function body so that the returned key can be stack-allocated.
161 mut privatekey := []u8{len: private_key_size}
162 new_key_from_seed_generic(mut privatekey, seed)
163 return PrivateKey(privatekey)
164}
165
166fn new_key_from_seed_generic(mut privatekey []u8, seed []u8) {
167 if seed.len != seed_size {
168 panic('ed25519: bad seed length: ${seed.len}')
169 }
170
171 mut h := sha512.sum512(seed)
172 mut s := edwards25519.new_scalar()
173 s.set_bytes_with_clamping(h[..32]) or { panic(err) }
174 mut aa := edwards25519.Point{}
175 aa.scalar_base_mult(mut s)
176
177 mut publickey := aa.bytes()
178
179 copy(mut privatekey, seed)
180 copy(mut privatekey[32..], publickey)
181}
182