| 1 | module ed25519 |
| 2 | |
| 3 | import crypto.rand |
| 4 | import crypto.sha512 |
| 5 | import crypto.internal.subtle |
| 6 | import crypto.ed25519.internal.edwards25519 |
| 7 | |
| 8 | // public_key_size is the sizeof public keys in bytes |
| 9 | pub const public_key_size = 32 |
| 10 | |
| 11 | // private_key_size is the sizeof private keys in bytes |
| 12 | pub const private_key_size = 64 |
| 13 | |
| 14 | // signature_size is the size of signatures generated and verified by this modules, in bytes. |
| 15 | pub const signature_size = 64 |
| 16 | |
| 17 | // seed_size is the size of private key seeds in bytes |
| 18 | pub const seed_size = 32 |
| 19 | |
| 20 | // `PublicKey` is Ed25519 public keys. |
| 21 | pub type PublicKey = []u8 |
| 22 | |
| 23 | // equal reports whether p and x have the same value. |
| 24 | pub 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 |
| 29 | pub 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. |
| 33 | pub 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. |
| 40 | pub 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` |
| 48 | pub 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. |
| 53 | pub 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 |
| 63 | pub 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 | |
| 69 | fn 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. |
| 111 | pub 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`. |
| 147 | pub 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 |
| 159 | pub 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 | |
| 166 | fn 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 | |