ed25519-zebra/src/secret_key.rs

125 lines
3.2 KiB
Rust
Raw Normal View History

2020-01-22 16:58:18 -08:00
use curve25519_dalek::{constants, scalar::Scalar};
2020-01-22 14:57:26 -08:00
use rand_core::{CryptoRng, RngCore};
2020-01-22 16:58:18 -08:00
use sha2::{Digest, Sha512};
2020-01-22 14:57:26 -08:00
2020-01-22 16:58:18 -08:00
use crate::{PublicKey, PublicKeyBytes, Signature};
2020-01-22 14:57:26 -08:00
/// An Ed25519 secret key.
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(from = "SerdeHelper"))]
#[cfg_attr(feature = "serde", serde(into = "SerdeHelper"))]
pub struct SecretKey {
2020-01-22 16:58:18 -08:00
seed: [u8; 32],
s: Scalar,
prefix: [u8; 32],
2020-01-22 14:57:26 -08:00
pk: PublicKey,
}
impl<'a> From<&'a SecretKey> for PublicKey {
fn from(sk: &'a SecretKey) -> PublicKey {
2020-01-22 17:03:46 -08:00
sk.pk
2020-01-22 14:57:26 -08:00
}
}
impl<'a> From<&'a SecretKey> for PublicKeyBytes {
fn from(sk: &'a SecretKey) -> PublicKeyBytes {
sk.pk.into()
}
}
impl AsRef<[u8]> for SecretKey {
fn as_ref(&self) -> &[u8] {
&self.seed[..]
}
}
2020-01-22 14:57:26 -08:00
impl From<SecretKey> for [u8; 32] {
2020-01-22 16:58:18 -08:00
fn from(sk: SecretKey) -> [u8; 32] {
sk.seed
2020-01-22 14:57:26 -08:00
}
}
impl From<[u8; 32]> for SecretKey {
2020-01-22 16:58:18 -08:00
#[allow(non_snake_case)]
fn from(seed: [u8; 32]) -> SecretKey {
// Expand the seed to a 64-byte array with SHA512.
let h = Sha512::digest(&seed[..]);
// Convert the low half to a scalar with Ed25519 "clamping"
let s = {
let mut scalar_bytes = [0u8; 32];
scalar_bytes[..].copy_from_slice(&h.as_slice()[0..32]);
scalar_bytes[0] &= 248;
scalar_bytes[31] &= 127;
scalar_bytes[31] |= 64;
Scalar::from_bits(scalar_bytes)
};
// Extract and cache the high half.
let prefix = {
let mut prefix = [0u8; 32];
prefix[..].copy_from_slice(&h.as_slice()[32..64]);
prefix
};
// Compute the public key as A = [s]B.
let A = &s * &constants::ED25519_BASEPOINT_TABLE;
SecretKey {
seed,
s,
prefix,
pk: PublicKey {
minus_A: -A,
A_bytes: PublicKeyBytes(A.compress().to_bytes()),
2020-01-22 16:58:18 -08:00
},
}
2020-01-22 14:57:26 -08:00
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
struct SerdeHelper([u8; 32]);
impl From<SerdeHelper> for SecretKey {
fn from(helper: SerdeHelper) -> SecretKey {
helper.0.into()
}
}
impl From<SecretKey> for SerdeHelper {
fn from(sk: SecretKey) -> Self {
Self(sk.into())
}
}
impl SecretKey {
/// Generate a new secret key.
2020-01-22 16:58:18 -08:00
pub fn new<R: RngCore + CryptoRng>(mut rng: R) -> SecretKey {
let mut bytes = [0u8; 32];
rng.fill_bytes(&mut bytes[..]);
bytes.into()
2020-01-22 14:57:26 -08:00
}
/// Create a signature on `msg` using this `SecretKey`.
2020-01-22 16:58:18 -08:00
#[allow(non_snake_case)]
pub fn sign(&self, msg: &[u8]) -> Signature {
let r = Scalar::from_hash(Sha512::default().chain(&self.prefix[..]).chain(msg));
let R_bytes = (&r * &constants::ED25519_BASEPOINT_TABLE)
.compress()
.to_bytes();
let k = Scalar::from_hash(
Sha512::default()
.chain(&R_bytes[..])
.chain(&self.pk.A_bytes.0[..])
2020-01-22 16:58:18 -08:00
.chain(msg),
);
let s_bytes = (r + k * self.s).to_bytes();
Signature { R_bytes, s_bytes }
2020-01-22 14:57:26 -08:00
}
}