This repository has been archived by the owner on Dec 22, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 28
/
seed.rs
128 lines (112 loc) · 3.86 KB
/
seed.rs
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
116
117
118
119
120
121
122
123
124
125
126
127
128
//! Ed25519 seeds: 32-bit uniformly random secret value used to derive scalars
//! and nonce prefixes
#[cfg(feature = "encoding")]
use crate::encoding::Decode;
#[cfg(all(feature = "alloc", feature = "encoding"))]
use crate::encoding::Encode;
#[cfg(all(feature = "encoding", feature = "alloc"))]
use alloc::vec::Vec;
#[cfg(feature = "getrandom")]
use getrandom::getrandom;
#[cfg(feature = "encoding")]
use subtle_encoding::Encoding;
use zeroize::Zeroize;
/// Size of the "seed" value for an Ed25519 private key
pub const SEED_SIZE: usize = 32;
/// Size of an Ed25519 keypair (private scalar + compressed Edwards-y public key)
pub const KEYPAIR_SIZE: usize = 64;
/// Ed25519 seeds: derivation secrets for Ed25519 private scalars/nonce prefixes
#[derive(Clone)]
pub struct Seed(pub [u8; SEED_SIZE]);
impl Seed {
/// Create an Ed25519 seed from a 32-byte array
pub fn new(bytes: [u8; SEED_SIZE]) -> Self {
Seed(bytes)
}
/// Generate a new Ed25519 seed using the operating system's
/// cryptographically secure random number generator
#[cfg(feature = "getrandom")]
pub fn generate() -> Self {
let mut bytes = [0u8; SEED_SIZE];
getrandom(&mut bytes[..]).expect("RNG failure!");
Self::new(bytes)
}
/// Create an Ed25519 seed from a byte slice, returning `KeyInvalid` if the
/// slice is not the correct size (32-bytes)
pub fn from_bytes<B>(bytes: B) -> Option<Self>
where
B: AsRef<[u8]>,
{
if bytes.as_ref().len() == SEED_SIZE {
let mut seed = [0u8; SEED_SIZE];
seed.copy_from_slice(bytes.as_ref());
Some(Seed::new(seed))
} else {
None
}
}
/// Create an Ed25519 seed from a keypair: i.e. a seed and its assocaited
/// public key (i.e. compressed Edwards-y coordinate)
pub fn from_keypair(keypair: &[u8]) -> Option<Self> {
if keypair.len() == KEYPAIR_SIZE {
// TODO: ensure public key part of keypair is correct
Self::from_bytes(&keypair[..SEED_SIZE])
} else {
None
}
}
/// Decode a `Seed` from an encoded (hex or Base64) Ed25519 keypair
#[cfg(feature = "encoding")]
pub fn decode_keypair<E: Encoding>(
encoded_keypair: &[u8],
encoding: &E,
) -> Result<Self, signature::Error> {
let mut decoded_keypair = [0u8; SEED_SIZE * 2];
let decoded_len = encoding
.decode_to_slice(encoded_keypair, &mut decoded_keypair)
.map_err(|_| signature::Error::new())?;
if decoded_len == SEED_SIZE * 2 {
Self::from_keypair(&decoded_keypair).ok_or_else(signature::Error::new)
} else {
Err(signature::Error::new())
}
}
/// Expose the secret values of the `Seed` as a byte slice
pub fn as_secret_slice(&self) -> &[u8] {
self.0.as_ref()
}
}
#[cfg(feature = "encoding")]
impl Decode for Seed {
/// Decode an Ed25519 seed from a byte slice with the given encoding
/// (e.g. hex, Base64)
fn decode<E: Encoding>(
encoded_seed: &[u8],
encoding: &E,
) -> Result<Self, crate::encoding::Error> {
let mut decoded_seed = [0u8; SEED_SIZE];
let decoded_len = encoding.decode_to_slice(encoded_seed, &mut decoded_seed)?;
if decoded_len == SEED_SIZE {
Ok(Self::new(decoded_seed))
} else {
Err(crate::encoding::error::ErrorKind::Decode)?
}
}
}
#[cfg(all(feature = "encoding", feature = "alloc"))]
impl Encode for Seed {
/// Encode an Ed25519 seed with the given encoding (e.g. hex, Base64)
fn encode<E: Encoding>(&self, encoding: &E) -> Vec<u8> {
encoding.encode(self.as_secret_slice())
}
}
impl Drop for Seed {
fn drop(&mut self) {
self.0.zeroize();
}
}
impl From<[u8; 32]> for Seed {
fn from(bytes: [u8; SEED_SIZE]) -> Self {
Seed::new(bytes)
}
}