risc0-curve25519-dalek-source/src/public.rs

286 lines
8.7 KiB
Rust
Raw Normal View History

2018-12-30 03:53:11 +00:00
// -*- mode: rust; -*-
//
// This file is part of ed25519-dalek.
// Copyright (c) 2017-2019 isis lovecruft
2018-12-30 03:53:11 +00:00
// See LICENSE for licensing information.
//
// Authors:
// - isis agora lovecruft <isis@patternsinthevoid.net>
//! ed25519 public keys.
use core::fmt::Debug;
use curve25519_dalek::constants;
use curve25519_dalek::digest::generic_array::typenum::U64;
2018-12-30 04:07:50 +00:00
use curve25519_dalek::digest::Digest;
2018-12-30 03:53:11 +00:00
use curve25519_dalek::edwards::CompressedEdwardsY;
use curve25519_dalek::edwards::EdwardsPoint;
use curve25519_dalek::scalar::Scalar;
pub use sha2::Sha512;
#[cfg(feature = "serde")]
use serde::de::Error as SerdeError;
#[cfg(feature = "serde")]
use serde::de::Visitor;
2018-12-30 04:07:50 +00:00
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "serde")]
use serde::{Deserializer, Serializer};
2018-12-30 03:53:11 +00:00
use crate::constants::*;
use crate::errors::*;
use crate::secret::*;
use crate::signature::*;
/// An ed25519 public key.
#[derive(Copy, Clone, Default, Eq, PartialEq)]
2018-12-30 04:07:50 +00:00
pub struct PublicKey(pub(crate) CompressedEdwardsY, pub(crate) EdwardsPoint);
2018-12-30 03:53:11 +00:00
impl Debug for PublicKey {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
write!(f, "PublicKey({:?}), {:?})", self.0, self.1)
}
}
impl AsRef<[u8]> for PublicKey {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl<'a> From<&'a SecretKey> for PublicKey {
/// Derive this public key from its corresponding `SecretKey`.
fn from(secret_key: &SecretKey) -> PublicKey {
2018-12-30 04:07:50 +00:00
let mut h: Sha512 = Sha512::new();
let mut hash: [u8; 64] = [0u8; 64];
2018-12-30 03:53:11 +00:00
let mut digest: [u8; 32] = [0u8; 32];
h.input(secret_key.as_bytes());
hash.copy_from_slice(h.result().as_slice());
digest.copy_from_slice(&hash[..32]);
PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest)
}
}
impl<'a> From<&'a ExpandedSecretKey> for PublicKey {
/// Derive this public key from its corresponding `ExpandedSecretKey`.
fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey {
let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes();
PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits)
}
}
impl PublicKey {
/// Convert this public key to a byte array.
#[inline]
pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] {
self.0.to_bytes()
}
/// View this public key as a byte array.
#[inline]
pub fn as_bytes<'a>(&'a self) -> &'a [u8; PUBLIC_KEY_LENGTH] {
&(self.0).0
}
/// Construct a `PublicKey` from a slice of bytes.
///
/// # Warning
///
/// The caller is responsible for ensuring that the bytes passed into this
/// method actually represent a `curve25519_dalek::curve::CompressedEdwardsY`
/// and that said compressed point is actually a point on the curve.
///
/// # Example
///
/// ```
/// # extern crate ed25519_dalek;
/// #
/// use ed25519_dalek::PublicKey;
/// use ed25519_dalek::PUBLIC_KEY_LENGTH;
/// use ed25519_dalek::SignatureError;
///
/// # fn doctest() -> Result<PublicKey, SignatureError> {
/// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [
/// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58,
/// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26];
///
/// let public_key = PublicKey::from_bytes(&public_key_bytes)?;
/// #
/// # Ok(public_key)
/// # }
/// #
/// # fn main() {
/// # doctest();
/// # }
/// ```
///
/// # Returns
///
/// A `Result` whose okay value is an EdDSA `PublicKey` or whose error value
/// is an `SignatureError` describing the error that occurred.
#[inline]
pub fn from_bytes(bytes: &[u8]) -> Result<PublicKey, SignatureError> {
if bytes.len() != PUBLIC_KEY_LENGTH {
2018-12-30 04:07:50 +00:00
return Err(SignatureError(InternalError::BytesLengthError {
name: "PublicKey",
length: PUBLIC_KEY_LENGTH,
}));
2018-12-30 03:53:11 +00:00
}
let mut bits: [u8; 32] = [0u8; 32];
bits.copy_from_slice(&bytes[..32]);
let compressed = CompressedEdwardsY(bits);
2018-12-30 04:07:50 +00:00
let point = compressed
.decompress()
.ok_or(SignatureError(InternalError::PointDecompressionError))?;
2018-12-30 03:53:11 +00:00
Ok(PublicKey(compressed, point))
}
/// Internal utility function for mangling the bits of a (formerly
/// mathematically well-defined) "scalar" and multiplying it to produce a
/// public key.
2018-12-30 04:07:50 +00:00
fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(
bits: &mut [u8; 32],
) -> PublicKey {
bits[0] &= 248;
2018-12-30 03:53:11 +00:00
bits[31] &= 127;
bits[31] |= 64;
let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE;
let compressed = point.compress();
PublicKey(compressed, point)
}
/// Verify a signature on a message with this keypair's public key.
///
/// # Return
///
/// Returns `Ok(())` if the signature is valid, and `Err` otherwise.
#[allow(non_snake_case)]
pub fn verify(
&self,
message: &[u8],
signature: &Signature
) -> Result<(), SignatureError>
{
let mut h: Sha512 = Sha512::new();
let R: EdwardsPoint;
let k: Scalar;
let minus_A: EdwardsPoint = -self.1;
h.input(signature.R.as_bytes());
h.input(self.as_bytes());
h.input(&message);
k = Scalar::from_hash(h);
R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s);
if R.compress() == signature.R {
Ok(())
} else {
Err(SignatureError(InternalError::VerifyError))
}
}
/// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm.
///
/// # Inputs
///
/// * `prehashed_message` is an instantiated hash digest with 512-bits of
/// output which has had the message to be signed previously fed into its
/// state.
/// * `context` is an optional context string, up to 255 bytes inclusive,
/// which may be used to provide additional domain separation. If not
/// set, this will default to an empty string.
/// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`.
///
/// # Returns
///
/// Returns `true` if the `signature` was a valid signature created by this
/// `Keypair` on the `prehashed_message`.
///
/// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
#[allow(non_snake_case)]
pub fn verify_prehashed<D>(
&self,
prehashed_message: D,
context: Option<&[u8]>,
signature: &Signature,
) -> Result<(), SignatureError>
2018-12-30 04:07:50 +00:00
where
D: Digest<OutputSize = U64>,
2018-12-30 03:53:11 +00:00
{
let mut h: Sha512 = Sha512::default();
let R: EdwardsPoint;
let k: Scalar;
let ctx: &[u8] = context.unwrap_or(b"");
debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets.");
let minus_A: EdwardsPoint = -self.1;
h.input(b"SigEd25519 no Ed25519 collisions");
h.input(&[1]); // Ed25519ph
h.input(&[ctx.len() as u8]);
h.input(ctx);
h.input(signature.R.as_bytes());
h.input(self.as_bytes());
h.input(prehashed_message.result().as_slice());
k = Scalar::from_hash(h);
R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s);
if R.compress() == signature.R {
Ok(())
} else {
Err(SignatureError(InternalError::VerifyError))
}
}
}
#[cfg(feature = "serde")]
impl Serialize for PublicKey {
2018-12-30 04:07:50 +00:00
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
2018-12-30 03:53:11 +00:00
serializer.serialize_bytes(self.as_bytes())
}
}
#[cfg(feature = "serde")]
impl<'d> Deserialize<'d> for PublicKey {
2018-12-30 04:07:50 +00:00
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'d>,
{
2018-12-30 03:53:11 +00:00
struct PublicKeyVisitor;
impl<'d> Visitor<'d> for PublicKeyVisitor {
type Value = PublicKey;
fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
2018-12-30 04:07:50 +00:00
formatter.write_str(
"An ed25519 public key as a 32-byte compressed point, as specified in RFC8032",
)
2018-12-30 03:53:11 +00:00
}
2018-12-30 04:07:50 +00:00
fn visit_bytes<E>(self, bytes: &[u8]) -> Result<PublicKey, E>
where
E: SerdeError,
{
2018-12-30 03:53:11 +00:00
PublicKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self)))
}
}
deserializer.deserialize_bytes(PublicKeyVisitor)
}
}