diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
commit | 10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch) | |
tree | bdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/ed25519-compact/src/ed25519.rs | |
parent | Releasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff) | |
download | rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip |
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/ed25519-compact/src/ed25519.rs')
-rw-r--r-- | vendor/ed25519-compact/src/ed25519.rs | 952 |
1 files changed, 952 insertions, 0 deletions
diff --git a/vendor/ed25519-compact/src/ed25519.rs b/vendor/ed25519-compact/src/ed25519.rs new file mode 100644 index 000000000..f03c77be0 --- /dev/null +++ b/vendor/ed25519-compact/src/ed25519.rs @@ -0,0 +1,952 @@ +use core::fmt; +use core::ops::{Deref, DerefMut}; + +use super::common::*; +#[cfg(feature = "blind-keys")] +use super::edwards25519::{ge_scalarmult, sc_invert, sc_mul}; +use super::edwards25519::{ + ge_scalarmult_base, is_identity, sc_muladd, sc_reduce, sc_reduce32, sc_reject_noncanonical, + GeP2, GeP3, +}; +use super::error::Error; +use super::sha512; + +/// A public key. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct PublicKey([u8; PublicKey::BYTES]); + +impl PublicKey { + /// Number of raw bytes in a public key. + pub const BYTES: usize = 32; + + /// Creates a public key from raw bytes. + pub fn new(pk: [u8; PublicKey::BYTES]) -> Self { + PublicKey(pk) + } + + /// Creates a public key from a slice. + pub fn from_slice(pk: &[u8]) -> Result<Self, Error> { + let mut pk_ = [0u8; PublicKey::BYTES]; + if pk.len() != pk_.len() { + return Err(Error::InvalidPublicKey); + } + pk_.copy_from_slice(pk); + Ok(PublicKey::new(pk_)) + } +} + +impl Deref for PublicKey { + type Target = [u8; PublicKey::BYTES]; + + /// Returns a public key as bytes. + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for PublicKey { + /// Returns a public key as mutable bytes. + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +/// A secret key. +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct SecretKey([u8; SecretKey::BYTES]); + +impl SecretKey { + /// Number of bytes in a secret key. + pub const BYTES: usize = 32 + PublicKey::BYTES; + + /// Creates a secret key from raw bytes. + pub fn new(sk: [u8; SecretKey::BYTES]) -> Self { + SecretKey(sk) + } + + /// Creates a secret key from a slice. + pub fn from_slice(sk: &[u8]) -> Result<Self, Error> { + let mut sk_ = [0u8; SecretKey::BYTES]; + if sk.len() != sk_.len() { + return Err(Error::InvalidSecretKey); + } + sk_.copy_from_slice(sk); + Ok(SecretKey::new(sk_)) + } + + /// Returns the public counterpart of a secret key. + pub fn public_key(&self) -> PublicKey { + let mut pk = [0u8; PublicKey::BYTES]; + pk.copy_from_slice(&self[Seed::BYTES..]); + PublicKey(pk) + } + + /// Returns the seed of a secret key. + pub fn seed(&self) -> Seed { + Seed::from_slice(&self[0..Seed::BYTES]).unwrap() + } + + /// Returns `Ok(())` if the given public key is the public counterpart of + /// this secret key. + /// Returns `Err(Error::InvalidPublicKey)` otherwise. + /// The public key is recomputed (not just copied) from the secret key, + /// so this will detect corruption of the secret key. + pub fn validate_public_key(&self, pk: &PublicKey) -> Result<(), Error> { + let kp = KeyPair::from_seed(self.seed()); + if kp.pk != *pk { + return Err(Error::InvalidPublicKey); + } + Ok(()) + } +} + +impl Drop for SecretKey { + fn drop(&mut self) { + Mem::wipe(self.0) + } +} + +impl Deref for SecretKey { + type Target = [u8; SecretKey::BYTES]; + + /// Returns a secret key as bytes. + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for SecretKey { + /// Returns a secret key as mutable bytes. + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +/// A key pair. +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct KeyPair { + /// Public key part of the key pair. + pub pk: PublicKey, + /// Secret key part of the key pair. + pub sk: SecretKey, +} + +/// An Ed25519 signature. +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +pub struct Signature([u8; Signature::BYTES]); + +impl fmt::Debug for Signature { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_fmt(format_args!("{:x?}", &self.0)) + } +} + +impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl Signature { + /// Number of raw bytes in a signature. + pub const BYTES: usize = 64; + + /// Creates a signature from raw bytes. + pub fn new(bytes: [u8; Signature::BYTES]) -> Self { + Signature(bytes) + } + + /// Creates a signature key from a slice. + pub fn from_slice(signature: &[u8]) -> Result<Self, Error> { + let mut signature_ = [0u8; Signature::BYTES]; + if signature.len() != signature_.len() { + return Err(Error::InvalidSignature); + } + signature_.copy_from_slice(signature); + Ok(Signature::new(signature_)) + } +} + +impl Deref for Signature { + type Target = [u8; Signature::BYTES]; + + /// Returns a signture as bytes. + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Signature { + /// Returns a signature as mutable bytes. + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +/// The state of a streaming verification operation. +#[derive(Clone)] +pub struct VerifyingState { + hasher: sha512::Hash, + signature: Signature, + a: GeP3, +} + +impl Drop for VerifyingState { + fn drop(&mut self) { + Mem::wipe(self.signature.0); + } +} + +impl VerifyingState { + fn new(pk: &PublicKey, signature: &Signature) -> Result<Self, Error> { + let r = &signature[0..32]; + let s = &signature[32..64]; + sc_reject_noncanonical(s)?; + if is_identity(pk) || pk.iter().fold(0, |acc, x| acc | x) == 0 { + return Err(Error::WeakPublicKey); + } + let a = match GeP3::from_bytes_negate_vartime(pk) { + Some(g) => g, + None => { + return Err(Error::InvalidPublicKey); + } + }; + let mut hasher = sha512::Hash::new(); + hasher.update(r); + hasher.update(&pk[..]); + Ok(VerifyingState { + hasher, + signature: *signature, + a, + }) + } + + /// Appends data to the message being verified. + pub fn absorb(&mut self, chunk: impl AsRef<[u8]>) { + self.hasher.update(chunk) + } + + /// Verifies the signature and return it. + pub fn verify(&self) -> Result<(), Error> { + let mut expected_r_bytes = [0u8; 32]; + expected_r_bytes.copy_from_slice(&self.signature[0..32]); + let expected_r = + GeP3::from_bytes_vartime(&expected_r_bytes).ok_or(Error::InvalidSignature)?; + let s = &self.signature[32..64]; + + let mut hash = self.hasher.finalize(); + sc_reduce(&mut hash); + + let r = GeP2::double_scalarmult_vartime(hash.as_ref(), self.a, s); + if (expected_r - GeP3::from(r)).has_small_order() { + Ok(()) + } else { + Err(Error::SignatureMismatch) + } + } +} + +impl PublicKey { + /// Verify the signature of a multi-part message (streaming). + pub fn verify_incremental(&self, signature: &Signature) -> Result<VerifyingState, Error> { + VerifyingState::new(self, signature) + } + + /// Verifies that the signature `signature` is valid for the message + /// `message`. + pub fn verify(&self, message: impl AsRef<[u8]>, signature: &Signature) -> Result<(), Error> { + let mut st = VerifyingState::new(self, signature)?; + st.absorb(message); + st.verify() + } +} + +/// The state of a streaming signature operation. +#[derive(Clone)] +pub struct SigningState { + hasher: sha512::Hash, + az: [u8; 64], + nonce: [u8; 64], +} + +impl Drop for SigningState { + fn drop(&mut self) { + Mem::wipe(self.az); + Mem::wipe(self.nonce); + } +} + +impl SigningState { + fn new(nonce: [u8; 64], az: [u8; 64], pk_: &[u8]) -> Self { + let mut prefix: [u8; 64] = [0; 64]; + let r = ge_scalarmult_base(&nonce[0..32]); + prefix[0..32].copy_from_slice(&r.to_bytes()[..]); + prefix[32..64].copy_from_slice(pk_); + + let mut st = sha512::Hash::new(); + st.update(prefix); + + SigningState { + hasher: st, + nonce, + az, + } + } + + /// Appends data to the message being signed. + pub fn absorb(&mut self, chunk: impl AsRef<[u8]>) { + self.hasher.update(chunk) + } + + /// Computes the signature and return it. + pub fn sign(&self) -> Signature { + let mut signature: [u8; 64] = [0; 64]; + let r = ge_scalarmult_base(&self.nonce[0..32]); + signature[0..32].copy_from_slice(&r.to_bytes()[..]); + let mut hram = self.hasher.finalize(); + sc_reduce(&mut hram); + sc_muladd( + &mut signature[32..64], + &hram[0..32], + &self.az[0..32], + &self.nonce[0..32], + ); + Signature(signature) + } +} + +impl SecretKey { + /// Sign a multi-part message (streaming API). + /// It is critical for `noise` to never repeat. + pub fn sign_incremental(&self, noise: Noise) -> SigningState { + let seed = &self[0..32]; + let pk = &self[32..64]; + let az: [u8; 64] = { + let mut hash_output = sha512::Hash::hash(seed); + hash_output[0] &= 248; + hash_output[31] &= 63; + hash_output[31] |= 64; + hash_output + }; + let mut st = sha512::Hash::new(); + #[cfg(feature = "random")] + { + let additional_noise = Noise::generate(); + st.update(additional_noise.as_ref()); + } + st.update(noise.as_ref()); + st.update(seed); + let nonce = st.finalize(); + SigningState::new(nonce, az, pk) + } + + /// Computes a signature for the message `message` using the secret key. + /// The noise parameter is optional, but recommended in order to mitigate + /// fault attacks. + pub fn sign(&self, message: impl AsRef<[u8]>, noise: Option<Noise>) -> Signature { + let seed = &self[0..32]; + let pk = &self[32..64]; + let az: [u8; 64] = { + let mut hash_output = sha512::Hash::hash(seed); + hash_output[0] &= 248; + hash_output[31] &= 63; + hash_output[31] |= 64; + hash_output + }; + let nonce = { + let mut hasher = sha512::Hash::new(); + if let Some(noise) = noise { + hasher.update(&noise[..]); + hasher.update(&az[..]); + } else { + hasher.update(&az[32..64]); + } + hasher.update(&message); + let mut hash_output = hasher.finalize(); + sc_reduce(&mut hash_output[0..64]); + hash_output + }; + let mut st = SigningState::new(nonce, az, pk); + st.absorb(&message); + let signature = st.sign(); + + #[cfg(feature = "self-verify")] + { + PublicKey::from_slice(pk) + .expect("Key length changed") + .verify(message, &signature) + .expect("Newly created signature cannot be verified"); + } + + signature + } +} + +impl KeyPair { + /// Number of bytes in a key pair. + pub const BYTES: usize = SecretKey::BYTES; + + /// Generates a new key pair. + #[cfg(feature = "random")] + pub fn generate() -> KeyPair { + KeyPair::from_seed(Seed::default()) + } + + /// Generates a new key pair using a secret seed. + pub fn from_seed(seed: Seed) -> KeyPair { + if seed.iter().fold(0, |acc, x| acc | x) == 0 { + panic!("All-zero seed"); + } + let (scalar, _) = { + let hash_output = sha512::Hash::hash(&seed[..]); + KeyPair::split(&hash_output, false, true) + }; + let pk = ge_scalarmult_base(&scalar).to_bytes(); + let mut sk = [0u8; 64]; + sk[0..32].copy_from_slice(&*seed); + sk[32..64].copy_from_slice(&pk); + KeyPair { + pk: PublicKey(pk), + sk: SecretKey(sk), + } + } + + /// Creates a key pair from a slice. + pub fn from_slice(bytes: &[u8]) -> Result<Self, Error> { + let sk = SecretKey::from_slice(bytes)?; + let pk = sk.public_key(); + Ok(KeyPair { pk, sk }) + } + + /// Clamp a scalar. + pub fn clamp(scalar: &mut [u8]) { + scalar[0] &= 248; + scalar[31] &= 63; + scalar[31] |= 64; + } + + /// Split a serialized representation of a key pair into a secret scalar and + /// a prefix. + pub fn split(bytes: &[u8; 64], reduce: bool, clamp: bool) -> ([u8; 32], [u8; 32]) { + let mut scalar = [0u8; 32]; + scalar.copy_from_slice(&bytes[0..32]); + if clamp { + Self::clamp(&mut scalar); + } + if reduce { + sc_reduce32(&mut scalar); + } + let mut prefix = [0u8; 32]; + prefix.copy_from_slice(&bytes[32..64]); + (scalar, prefix) + } + + /// Check that the public key is valid for the secret key. + pub fn validate(&self) -> Result<(), Error> { + self.sk.validate_public_key(&self.pk) + } +} + +impl Deref for KeyPair { + type Target = [u8; KeyPair::BYTES]; + + /// Returns a key pair as bytes. + fn deref(&self) -> &Self::Target { + &self.sk + } +} + +impl DerefMut for KeyPair { + /// Returns a key pair as mutable bytes. + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.sk + } +} + +/// Noise, for non-deterministic signatures. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct Noise([u8; Noise::BYTES]); + +impl Noise { + /// Number of raw bytes for a noise component. + pub const BYTES: usize = 16; + + /// Creates a new noise component from raw bytes. + pub fn new(noise: [u8; Noise::BYTES]) -> Self { + Noise(noise) + } + + /// Creates noise from a slice. + pub fn from_slice(noise: &[u8]) -> Result<Self, Error> { + let mut noise_ = [0u8; Noise::BYTES]; + if noise.len() != noise_.len() { + return Err(Error::InvalidSeed); + } + noise_.copy_from_slice(noise); + Ok(Noise::new(noise_)) + } +} + +impl Deref for Noise { + type Target = [u8; Noise::BYTES]; + + /// Returns the noise as bytes. + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Noise { + /// Returns the noise as mutable bytes. + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[cfg(feature = "random")] +impl Default for Noise { + /// Generates random noise. + fn default() -> Self { + let mut noise = [0u8; Noise::BYTES]; + getrandom::getrandom(&mut noise).expect("RNG failure"); + Noise(noise) + } +} + +#[cfg(feature = "random")] +impl Noise { + /// Generates random noise. + pub fn generate() -> Self { + Noise::default() + } +} + +#[cfg(feature = "traits")] +mod ed25519_trait { + use ::ed25519::signature as ed25519_trait; + + use super::{PublicKey, SecretKey, Signature}; + + impl ed25519_trait::Signature for Signature { + fn from_bytes(bytes: &[u8]) -> Result<Self, ed25519_trait::Error> { + let mut bytes_ = [0u8; Signature::BYTES]; + bytes_.copy_from_slice(bytes); + Ok(Signature::new(bytes_)) + } + } + + impl ed25519_trait::Signer<Signature> for SecretKey { + fn try_sign(&self, message: &[u8]) -> Result<Signature, ed25519_trait::Error> { + Ok(self.sign(message, None)) + } + } + + impl ed25519_trait::Verifier<Signature> for PublicKey { + fn verify( + &self, + message: &[u8], + signature: &Signature, + ) -> Result<(), ed25519_trait::Error> { + #[cfg(feature = "std")] + { + self.verify(message, signature) + .map_err(|e| ed25519_trait::Error::from_source(e)) + } + + #[cfg(not(feature = "std"))] + { + self.verify(message, signature) + .map_err(|_| ed25519_trait::Error::new()) + } + } + } +} + +#[test] +fn test_ed25519() { + let kp = KeyPair::from_seed([42u8; 32].into()); + let message = b"Hello, World!"; + let signature = kp.sk.sign(message, None); + assert!(kp.pk.verify(message, &signature).is_ok()); + assert!(kp.pk.verify(b"Hello, world!", &signature).is_err()); + assert_eq!( + signature.as_ref(), + [ + 196, 182, 1, 15, 182, 182, 231, 166, 227, 62, 243, 85, 49, 174, 169, 9, 162, 196, 98, + 104, 30, 81, 22, 38, 184, 136, 253, 128, 10, 160, 128, 105, 127, 130, 138, 164, 57, 86, + 94, 160, 216, 85, 153, 139, 81, 100, 38, 124, 235, 210, 26, 95, 231, 90, 73, 206, 33, + 216, 171, 15, 188, 181, 136, 7, + ] + ); +} + +#[cfg(feature = "blind-keys")] +mod blind_keys { + use super::*; + + #[derive(Clone, Debug, Eq, PartialEq, Hash)] + pub struct Blind([u8; Blind::BYTES]); + + impl From<[u8; 32]> for Blind { + fn from(blind: [u8; 32]) -> Self { + Blind(blind) + } + } + + impl Blind { + /// Number of raw bytes in a blind. + pub const BYTES: usize = 32; + + /// Creates a blind from raw bytes. + pub fn new(blind: [u8; Blind::BYTES]) -> Self { + Blind(blind) + } + + /// Creates a blind from a slice. + pub fn from_slice(blind: &[u8]) -> Result<Self, Error> { + let mut blind_ = [0u8; Blind::BYTES]; + if blind.len() != blind_.len() { + return Err(Error::InvalidBlind); + } + blind_.copy_from_slice(blind); + Ok(Blind::new(blind_)) + } + } + + impl Drop for Blind { + fn drop(&mut self) { + Mem::wipe(self.0) + } + } + + #[cfg(feature = "random")] + impl Default for Blind { + /// Generates a random blind. + fn default() -> Self { + let mut blind = [0u8; Blind::BYTES]; + getrandom::getrandom(&mut blind).expect("RNG failure"); + Blind(blind) + } + } + + #[cfg(feature = "random")] + impl Blind { + /// Generates a random blind. + pub fn generate() -> Self { + Blind::default() + } + } + + impl Deref for Blind { + type Target = [u8; Blind::BYTES]; + + /// Returns a blind as bytes. + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl DerefMut for Blind { + /// Returns a blind as mutable bytes. + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + /// A blind public key. + #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] + pub struct BlindPublicKey([u8; PublicKey::BYTES]); + + impl Deref for BlindPublicKey { + type Target = [u8; BlindPublicKey::BYTES]; + + /// Returns a public key as bytes. + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl DerefMut for BlindPublicKey { + /// Returns a public key as mutable bytes. + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + impl BlindPublicKey { + /// Number of bytes in a blind public key. + pub const BYTES: usize = PublicKey::BYTES; + + /// Creates a blind public key from raw bytes. + pub fn new(bpk: [u8; PublicKey::BYTES]) -> Self { + BlindPublicKey(bpk) + } + + /// Creates a blind public key from a slice. + pub fn from_slice(bpk: &[u8]) -> Result<Self, Error> { + let mut bpk_ = [0u8; PublicKey::BYTES]; + if bpk.len() != bpk_.len() { + return Err(Error::InvalidPublicKey); + } + bpk_.copy_from_slice(bpk); + Ok(BlindPublicKey::new(bpk_)) + } + + /// Unblinds a public key. + pub fn unblind(&self, blind: &Blind, ctx: impl AsRef<[u8]>) -> Result<PublicKey, Error> { + let pk_p3 = GeP3::from_bytes_vartime(&self.0).ok_or(Error::InvalidPublicKey)?; + let mut hx = sha512::Hash::new(); + hx.update(&blind[..]); + hx.update([0u8]); + hx.update(ctx.as_ref()); + let hash_output = hx.finalize(); + let (blind_factor, _) = KeyPair::split(&hash_output, true, false); + let inverse = sc_invert(&blind_factor); + Ok(PublicKey(ge_scalarmult(&inverse, &pk_p3).to_bytes())) + } + + /// Verifies that the signature `signature` is valid for the message + /// `message`. + pub fn verify( + &self, + message: impl AsRef<[u8]>, + signature: &Signature, + ) -> Result<(), Error> { + PublicKey::new(self.0).verify(message, signature) + } + } + + impl From<PublicKey> for BlindPublicKey { + fn from(pk: PublicKey) -> Self { + BlindPublicKey(pk.0) + } + } + + impl From<BlindPublicKey> for PublicKey { + fn from(bpk: BlindPublicKey) -> Self { + PublicKey(bpk.0) + } + } + + /// A blind secret key. + #[derive(Clone, Debug, Eq, PartialEq, Hash)] + pub struct BlindSecretKey { + pub prefix: [u8; 2 * Seed::BYTES], + pub blind_scalar: [u8; 32], + pub blind_pk: BlindPublicKey, + } + + #[derive(Clone, Debug, Eq, PartialEq, Hash)] + pub struct BlindKeyPair { + /// Public key part of the blind key pair. + pub blind_pk: BlindPublicKey, + /// Secret key part of the blind key pair. + pub blind_sk: BlindSecretKey, + } + + impl BlindSecretKey { + /// Computes a signature for the message `message` using the blind + /// secret key. The noise parameter is optional, but recommended + /// in order to mitigate fault attacks. + pub fn sign(&self, message: impl AsRef<[u8]>, noise: Option<Noise>) -> Signature { + let nonce = { + let mut hasher = sha512::Hash::new(); + if let Some(noise) = noise { + hasher.update(&noise[..]); + hasher.update(self.prefix); + } else { + hasher.update(self.prefix); + } + hasher.update(&message); + let mut hash_output = hasher.finalize(); + sc_reduce(&mut hash_output[0..64]); + hash_output + }; + let mut signature: [u8; 64] = [0; 64]; + let r = ge_scalarmult_base(&nonce[0..32]); + signature[0..32].copy_from_slice(&r.to_bytes()[..]); + signature[32..64].copy_from_slice(&self.blind_pk.0); + let mut hasher = sha512::Hash::new(); + hasher.update(signature.as_ref()); + hasher.update(&message); + let mut hram = hasher.finalize(); + sc_reduce(&mut hram); + sc_muladd( + &mut signature[32..64], + &hram[0..32], + &self.blind_scalar, + &nonce[0..32], + ); + let signature = Signature(signature); + + #[cfg(feature = "self-verify")] + { + PublicKey::from_slice(&self.blind_pk.0) + .expect("Key length changed") + .verify(message, &signature) + .expect("Newly created signature cannot be verified"); + } + signature + } + } + + impl Drop for BlindSecretKey { + fn drop(&mut self) { + Mem::wipe(self.prefix); + Mem::wipe(self.blind_scalar); + } + } + + impl PublicKey { + /// Returns a blind version of the public key. + pub fn blind(&self, blind: &Blind, ctx: impl AsRef<[u8]>) -> Result<BlindPublicKey, Error> { + let (blind_factor, _prefix2) = { + let mut hx = sha512::Hash::new(); + hx.update(&blind[..]); + hx.update([0u8]); + hx.update(ctx.as_ref()); + let hash_output = hx.finalize(); + KeyPair::split(&hash_output, true, false) + }; + let pk_p3 = GeP3::from_bytes_vartime(&self.0).ok_or(Error::InvalidPublicKey)?; + Ok(BlindPublicKey( + ge_scalarmult(&blind_factor, &pk_p3).to_bytes(), + )) + } + } + + impl KeyPair { + /// Returns a blind version of the key pair. + pub fn blind(&self, blind: &Blind, ctx: impl AsRef<[u8]>) -> BlindKeyPair { + let seed = self.sk.seed(); + let (scalar, prefix1) = { + let hash_output = sha512::Hash::hash(&seed[..]); + KeyPair::split(&hash_output, false, true) + }; + + let (blind_factor, prefix2) = { + let mut hx = sha512::Hash::new(); + hx.update(&blind[..]); + hx.update([0u8]); + hx.update(ctx.as_ref()); + let hash_output = hx.finalize(); + KeyPair::split(&hash_output, true, false) + }; + + let blind_scalar = sc_mul(&scalar, &blind_factor); + let blind_pk = ge_scalarmult_base(&blind_scalar).to_bytes(); + + let mut prefix = [0u8; 2 * Seed::BYTES]; + prefix[0..32].copy_from_slice(&prefix1); + prefix[32..64].copy_from_slice(&prefix2); + let blind_pk = BlindPublicKey::new(blind_pk); + + BlindKeyPair { + blind_pk, + blind_sk: BlindSecretKey { + prefix, + blind_scalar, + blind_pk, + }, + } + } + } +} + +#[cfg(feature = "blind-keys")] +pub use blind_keys::*; + +#[test] +#[cfg(feature = "blind-keys")] +fn test_blind_ed25519() { + use ct_codecs::{Decoder, Hex}; + + let kp = KeyPair::generate(); + let blind = Blind::new([69u8; 32]); + let blind_kp = kp.blind(&blind, "ctx"); + let message = b"Hello, World!"; + let signature = blind_kp.blind_sk.sign(message, None); + assert!(blind_kp.blind_pk.verify(message, &signature).is_ok()); + let recovered_pk = blind_kp.blind_pk.unblind(&blind, "ctx").unwrap(); + assert!(recovered_pk == kp.pk); + + let kp = KeyPair::from_seed( + Seed::from_slice( + &Hex::decode_to_vec( + "875532ab039b0a154161c284e19c74afa28d5bf5454e99284bbcffaa71eebf45", + None, + ) + .unwrap(), + ) + .unwrap(), + ); + assert_eq!( + Hex::decode_to_vec( + "3b5983605b277cd44918410eb246bb52d83adfc806ccaa91a60b5b2011bc5973", + None + ) + .unwrap(), + kp.pk.as_ref() + ); + + let blind = Blind::from_slice( + &Hex::decode_to_vec( + "c461e8595f0ac41d374f878613206704978115a226f60470ffd566e9e6ae73bf", + None, + ) + .unwrap(), + ) + .unwrap(); + let blind_kp = kp.blind(&blind, "ctx"); + assert_eq!( + Hex::decode_to_vec( + "246dcd43930b81d5e4d770db934a9fcd985b75fd014bc2a98b0aea02311c1836", + None + ) + .unwrap(), + blind_kp.blind_pk.as_ref() + ); + + let message = Hex::decode_to_vec("68656c6c6f20776f726c64", None).unwrap(); + let signature = blind_kp.blind_sk.sign(message, None); + assert_eq!(Hex::decode_to_vec("947bacfabc63448f8955dc20630e069e58f37b72bb433ae17f2fa904ea860b44deb761705a3cc2168a6673ee0b41ff7765c7a4896941eec6833c1689315acb0b", + None).unwrap(), signature.as_ref()); +} + +#[test] +fn test_streaming() { + let kp = KeyPair::generate(); + + let msg1 = "mes"; + let msg2 = "sage"; + let mut st = kp.sk.sign_incremental(Noise::default()); + st.absorb(msg1); + st.absorb(msg2); + let signature = st.sign(); + + let msg1 = "mess"; + let msg2 = "age"; + let mut st = kp.pk.verify_incremental(&signature).unwrap(); + st.absorb(msg1); + st.absorb(msg2); + assert!(st.verify().is_ok()); +} + +#[test] +#[cfg(feature = "random")] +fn test_ed25519_invalid_keypair() { + let kp1 = KeyPair::generate(); + let kp2 = KeyPair::generate(); + + assert_eq!( + kp1.sk.validate_public_key(&kp2.pk).unwrap_err(), + Error::InvalidPublicKey + ); + assert_eq!( + kp2.sk.validate_public_key(&kp1.pk).unwrap_err(), + Error::InvalidPublicKey + ); + assert!(kp1.sk.validate_public_key(&kp1.pk).is_ok()); + assert!(kp2.sk.validate_public_key(&kp2.pk).is_ok()); + assert!(kp1.validate().is_ok()); +} |