Change from_bytes methods to take fixed-size array argument

Change from_bytes methods to take `&[u8; N]` argument (with `N`
appropriate for given type) rather than `&[u8]`.  This harmonises
the convention with SigningKey and ed25519::Signature; helps type
inference; and allows users to assert bytes size to be asserted at
compile time.

Creating from a slice is still possible via `TryFrom<&[u8]>` trait.

This is an API breaking change.  The simplest way to update existing
code is to replace Foo::from_bytes with Foo::try_from.  This should
cover majority of uses.
This commit is contained in:
Michal Nazarewicz 2022-12-02 05:55:16 +01:00
parent 52da7353b8
commit 24cd9421d5
4 changed files with 39 additions and 69 deletions

View file

@ -162,30 +162,12 @@ impl InternalSignature {
/// only checking the most significant three bits. (See also the /// only checking the most significant three bits. (See also the
/// documentation for `PublicKey.verify_strict`.) /// documentation for `PublicKey.verify_strict`.)
#[inline] #[inline]
pub fn from_bytes(bytes: &[u8]) -> Result<InternalSignature, SignatureError> { pub fn from_bytes(bytes: &[u8; SIGNATURE_LENGTH]) -> Result<InternalSignature, SignatureError> {
if bytes.len() != SIGNATURE_LENGTH { // TODO: Use bytes.split_array_ref once its in MSRV.
return Err(InternalError::BytesLengthError { let (lower, upper) = bytes.split_at(32);
name: "Signature",
length: SIGNATURE_LENGTH,
}
.into());
}
let mut lower: [u8; 32] = [0u8; 32];
let mut upper: [u8; 32] = [0u8; 32];
lower.copy_from_slice(&bytes[..32]);
upper.copy_from_slice(&bytes[32..]);
let s: Scalar;
match check_scalar(upper) {
Ok(x) => s = x,
Err(x) => return Err(x),
}
Ok(InternalSignature { Ok(InternalSignature {
R: CompressedEdwardsY(lower), R: CompressedEdwardsY(lower.try_into().unwrap()),
s: s, s: check_scalar(upper.try_into().unwrap())?,
}) })
} }
} }

View file

@ -122,17 +122,10 @@ impl SigningKey {
/// is an `SignatureError` describing the error that occurred. /// is an `SignatureError` describing the error that occurred.
#[inline] #[inline]
pub fn from_keypair_bytes(bytes: &[u8; 64]) -> Result<SigningKey, SignatureError> { pub fn from_keypair_bytes(bytes: &[u8; 64]) -> Result<SigningKey, SignatureError> {
if bytes.len() != KEYPAIR_LENGTH { // TODO: Use bytes.split_array_ref once its in MSRV.
return Err(InternalError::BytesLengthError { let (secret_key, verifying_key) = bytes.split_at(SECRET_KEY_LENGTH);
name: "SigningKey", let secret_key = secret_key.try_into().unwrap();
length: KEYPAIR_LENGTH, let verifying_key = VerifyingKey::from_bytes(verifying_key.try_into().unwrap())?;
}
.into());
}
let secret_key =
SecretKey::try_from(&bytes[..SECRET_KEY_LENGTH]).map_err(|_| SignatureError::new())?;
let verifying_key = VerifyingKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?;
if verifying_key != VerifyingKey::from(&secret_key) { if verifying_key != VerifyingKey::from(&secret_key) {
return Err(InternalError::MismatchedKeypairError.into()); return Err(InternalError::MismatchedKeypairError.into());

View file

@ -129,18 +129,8 @@ impl VerifyingKey {
/// A `Result` whose okay value is an EdDSA `VerifyingKey` or whose error value /// A `Result` whose okay value is an EdDSA `VerifyingKey` or whose error value
/// is an `SignatureError` describing the error that occurred. /// is an `SignatureError` describing the error that occurred.
#[inline] #[inline]
pub fn from_bytes(bytes: &[u8]) -> Result<VerifyingKey, SignatureError> { pub fn from_bytes(bytes: &[u8; PUBLIC_KEY_LENGTH]) -> Result<VerifyingKey, SignatureError> {
if bytes.len() != PUBLIC_KEY_LENGTH { let compressed = CompressedEdwardsY(*bytes);
return Err(InternalError::BytesLengthError {
name: "VerifyingKey",
length: PUBLIC_KEY_LENGTH,
}
.into());
}
let mut bits: [u8; 32] = [0u8; 32];
bits.copy_from_slice(&bytes[..32]);
let compressed = CompressedEdwardsY(bits);
let point = compressed let point = compressed
.decompress() .decompress()
.ok_or(InternalError::PointDecompressionError)?; .ok_or(InternalError::PointDecompressionError)?;
@ -358,11 +348,19 @@ impl Verifier<ed25519::Signature> for VerifyingKey {
impl TryFrom<&[u8]> for VerifyingKey { impl TryFrom<&[u8]> for VerifyingKey {
type Error = SignatureError; type Error = SignatureError;
fn try_from(bytes: &[u8]) -> Result<VerifyingKey, SignatureError> { #[inline]
VerifyingKey::from_bytes(bytes) fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let bytes = bytes.try_into().map_err(|_| {
InternalError::BytesLengthError {
name: "VerifyingKey",
length: PUBLIC_KEY_LENGTH,
}
})?;
Self::from_bytes(bytes)
} }
} }
#[cfg(feature = "pkcs8")] #[cfg(feature = "pkcs8")]
impl DecodePublicKey for VerifyingKey {} impl DecodePublicKey for VerifyingKey {}
@ -431,6 +429,6 @@ impl<'d> Deserialize<'d> for VerifyingKey {
D: Deserializer<'d>, D: Deserializer<'d>,
{ {
let bytes = <SerdeByteBuf>::deserialize(deserializer)?; let bytes = <SerdeByteBuf>::deserialize(deserializer)?;
VerifyingKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) VerifyingKey::try_from(bytes.as_ref()).map_err(SerdeError::custom)
} }
} }

View file

@ -14,6 +14,7 @@ use curve25519_dalek;
use ed25519_dalek::*; use ed25519_dalek::*;
use hex::FromHex; use hex::FromHex;
use hex_literal::hex;
use sha2::Sha512; use sha2::Sha512;
@ -61,9 +62,12 @@ mod vectors {
let msg_bytes: Vec<u8> = FromHex::from_hex(&parts[2]).unwrap(); let msg_bytes: Vec<u8> = FromHex::from_hex(&parts[2]).unwrap();
let sig_bytes: Vec<u8> = FromHex::from_hex(&parts[3]).unwrap(); let sig_bytes: Vec<u8> = FromHex::from_hex(&parts[3]).unwrap();
let signing_key = SigningKey::try_from(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); let sec_bytes = &sec_bytes[..SECRET_KEY_LENGTH].try_into().unwrap();
let pub_bytes = &pub_bytes[..PUBLIC_KEY_LENGTH].try_into().unwrap();
let signing_key = SigningKey::from_bytes(sec_bytes);
let expected_verifying_key = let expected_verifying_key =
VerifyingKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); VerifyingKey::from_bytes(pub_bytes).unwrap();
assert_eq!(expected_verifying_key, signing_key.verifying_key()); assert_eq!(expected_verifying_key, signing_key.verifying_key());
// The signatures in the test vectors also include the message // The signatures in the test vectors also include the message
@ -83,26 +87,19 @@ mod vectors {
// From https://tools.ietf.org/html/rfc8032#section-7.3 // From https://tools.ietf.org/html/rfc8032#section-7.3
#[test] #[test]
fn ed25519ph_rf8032_test_vector() { fn ed25519ph_rf8032_test_vector() {
let secret_key: &[u8] = b"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"; let sec_bytes = hex!("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42");
let verifying_key: &[u8] = let pub_bytes = hex!("ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf");
b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"; let msg_bytes = hex!("616263");
let message: &[u8] = b"616263"; let sig_bytes = hex!("98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406");
let signature: &[u8] = b"98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406";
let sec_bytes: Vec<u8> = FromHex::from_hex(secret_key).unwrap(); let signing_key = SigningKey::from_bytes(&sec_bytes);
let pub_bytes: Vec<u8> = FromHex::from_hex(verifying_key).unwrap(); let expected_verifying_key =
let msg_bytes: Vec<u8> = FromHex::from_hex(message).unwrap(); VerifyingKey::from_bytes(&pub_bytes).unwrap();
let sig_bytes: Vec<u8> = FromHex::from_hex(signature).unwrap();
let signing_key: SigningKey =
SigningKey::try_from(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap();
let expected_verifying_key: VerifyingKey =
VerifyingKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap();
assert_eq!(expected_verifying_key, signing_key.verifying_key()); assert_eq!(expected_verifying_key, signing_key.verifying_key());
let sig1: Signature = Signature::try_from(&sig_bytes[..]).unwrap(); let sig1 = Signature::try_from(&sig_bytes[..]).unwrap();
let mut prehash_for_signing: Sha512 = Sha512::default(); let mut prehash_for_signing = Sha512::default();
let mut prehash_for_verifying: Sha512 = Sha512::default(); let mut prehash_for_verifying = Sha512::default();
prehash_for_signing.update(&msg_bytes[..]); prehash_for_signing.update(&msg_bytes[..]);
prehash_for_verifying.update(&msg_bytes[..]); prehash_for_verifying.update(&msg_bytes[..]);
@ -187,7 +184,7 @@ mod vectors {
} }
let signature = serialize_signature(&r, &s); let signature = serialize_signature(&r, &s);
let pk = VerifyingKey::from_bytes(&pub_key.compress().as_bytes()[..]).unwrap(); let pk = VerifyingKey::from_bytes(&pub_key.compress().as_bytes()).unwrap();
let sig = Signature::try_from(&signature[..]).unwrap(); let sig = Signature::try_from(&signature[..]).unwrap();
// The same signature verifies for both messages // The same signature verifies for both messages
assert!(pk.verify(message1, &sig).is_ok() && pk.verify(message2, &sig).is_ok()); assert!(pk.verify(message1, &sig).is_ok() && pk.verify(message2, &sig).is_ok());