2020-07-06 19:05:51 -07:00
|
|
|
use std::convert::TryFrom;
|
|
|
|
|
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-07-06 19:05:51 -07:00
|
|
|
use crate::{Error, Signature, VerificationKey, VerificationKeyBytes};
|
2020-01-22 14:57:26 -08:00
|
|
|
|
2020-06-15 20:45:25 -07:00
|
|
|
/// An Ed25519 signing key.
|
|
|
|
///
|
|
|
|
/// This is also called a secret key by other implementations.
|
2020-06-09 17:06:17 -07:00
|
|
|
#[derive(Copy, Clone)]
|
2020-01-22 14:57:26 -08:00
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
#[cfg_attr(feature = "serde", serde(from = "SerdeHelper"))]
|
|
|
|
#[cfg_attr(feature = "serde", serde(into = "SerdeHelper"))]
|
2020-06-15 20:45:25 -07:00
|
|
|
pub struct SigningKey {
|
2020-01-22 16:58:18 -08:00
|
|
|
seed: [u8; 32],
|
|
|
|
s: Scalar,
|
|
|
|
prefix: [u8; 32],
|
2020-06-15 20:45:25 -07:00
|
|
|
vk: VerificationKey,
|
2020-01-22 14:57:26 -08:00
|
|
|
}
|
|
|
|
|
2020-06-15 20:45:25 -07:00
|
|
|
impl core::fmt::Debug for SigningKey {
|
2020-06-09 17:06:17 -07:00
|
|
|
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
|
2020-06-15 20:45:25 -07:00
|
|
|
fmt.debug_struct("SigningKey")
|
2020-06-09 17:06:17 -07:00
|
|
|
.field("seed", &hex::encode(&self.seed))
|
|
|
|
.field("s", &self.s)
|
|
|
|
.field("prefix", &hex::encode(&self.prefix))
|
2020-06-15 20:45:25 -07:00
|
|
|
.field("vk", &self.vk)
|
2020-06-09 17:06:17 -07:00
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-15 20:45:25 -07:00
|
|
|
impl<'a> From<&'a SigningKey> for VerificationKey {
|
|
|
|
fn from(sk: &'a SigningKey) -> VerificationKey {
|
|
|
|
sk.vk
|
2020-01-22 14:57:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-15 20:45:25 -07:00
|
|
|
impl<'a> From<&'a SigningKey> for VerificationKeyBytes {
|
|
|
|
fn from(sk: &'a SigningKey) -> VerificationKeyBytes {
|
|
|
|
sk.vk.into()
|
2020-01-28 17:29:51 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-15 20:45:25 -07:00
|
|
|
impl AsRef<[u8]> for SigningKey {
|
2020-04-01 19:11:29 -07:00
|
|
|
fn as_ref(&self) -> &[u8] {
|
|
|
|
&self.seed[..]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-15 20:45:25 -07:00
|
|
|
impl From<SigningKey> for [u8; 32] {
|
|
|
|
fn from(sk: SigningKey) -> [u8; 32] {
|
2020-01-22 16:58:18 -08:00
|
|
|
sk.seed
|
2020-01-22 14:57:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-06 19:05:51 -07:00
|
|
|
impl TryFrom<&[u8]> for SigningKey {
|
|
|
|
type Error = Error;
|
|
|
|
fn try_from(slice: &[u8]) -> Result<SigningKey, Error> {
|
|
|
|
if slice.len() == 32 {
|
|
|
|
let mut bytes = [0u8; 32];
|
|
|
|
bytes[..].copy_from_slice(slice);
|
|
|
|
Ok(bytes.into())
|
|
|
|
} else {
|
|
|
|
Err(Error::InvalidSliceLength)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-15 20:45:25 -07:00
|
|
|
impl From<[u8; 32]> for SigningKey {
|
2020-01-22 16:58:18 -08:00
|
|
|
#[allow(non_snake_case)]
|
2020-06-15 20:45:25 -07:00
|
|
|
fn from(seed: [u8; 32]) -> SigningKey {
|
2020-01-22 16:58:18 -08:00
|
|
|
// 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;
|
|
|
|
|
2020-06-15 20:45:25 -07:00
|
|
|
SigningKey {
|
2020-01-22 16:58:18 -08:00
|
|
|
seed,
|
|
|
|
s,
|
|
|
|
prefix,
|
2020-06-15 20:45:25 -07:00
|
|
|
vk: VerificationKey {
|
2020-01-22 17:02:45 -08:00
|
|
|
minus_A: -A,
|
2020-06-15 20:45:25 -07:00
|
|
|
A_bytes: VerificationKeyBytes(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]);
|
|
|
|
|
2020-06-15 20:45:25 -07:00
|
|
|
impl From<SerdeHelper> for SigningKey {
|
|
|
|
fn from(helper: SerdeHelper) -> SigningKey {
|
2020-01-22 14:57:26 -08:00
|
|
|
helper.0.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-15 20:45:25 -07:00
|
|
|
impl From<SigningKey> for SerdeHelper {
|
|
|
|
fn from(sk: SigningKey) -> Self {
|
2020-01-22 14:57:26 -08:00
|
|
|
Self(sk.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-15 20:45:25 -07:00
|
|
|
impl SigningKey {
|
|
|
|
/// Generate a new signing key.
|
|
|
|
pub fn new<R: RngCore + CryptoRng>(mut rng: R) -> SigningKey {
|
2020-01-22 16:58:18 -08:00
|
|
|
let mut bytes = [0u8; 32];
|
|
|
|
rng.fill_bytes(&mut bytes[..]);
|
|
|
|
bytes.into()
|
2020-01-22 14:57:26 -08:00
|
|
|
}
|
|
|
|
|
2020-06-15 20:45:25 -07:00
|
|
|
/// Create a signature on `msg` using this key.
|
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[..])
|
2020-06-15 20:45:25 -07:00
|
|
|
.chain(&self.vk.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
|
|
|
}
|
|
|
|
}
|