Publish / publish (release) Successful in 1m2s
Rust CI / cargo fmt (push) Successful in 3s
Rust CI / test (stable / no backend / no frontend) (push) Successful in 2m31s
Rust CI / cargo clippy (push) Successful in 1m24s
Rust CI / test (1.90.0 / no backend / no frontend) (push) Successful in 2m28s
Rust CI / test (1.90.0 / no backend / --features argon2) (push) Successful in 2m35s
Rust CI / test (stable / no backend / --features argon2) (push) Successful in 2m33s
Rust CI / test (1.90.0 / no backend / --features serde) (push) Successful in 2m53s
Rust CI / test (1.90.0 / --features curve25519 / --features argon2) (push) Successful in 2m36s
Rust CI / test (stable / no backend / --features serde) (push) Successful in 2m51s
Rust CI / test (1.90.0 / --features curve25519 / no frontend) (push) Successful in 2m29s
Rust CI / test (stable / --features curve25519 / no frontend) (push) Successful in 2m29s
Rust CI / test (stable / --features curve25519 / --features serde) (push) Successful in 2m55s
Rust CI / test (stable / --features curve25519 / --features argon2) (push) Successful in 2m35s
Rust CI / test (1.90.0 / --features curve25519 / --features serde) (push) Successful in 2m56s
Rust CI / test (stable / --features ecdsa / no frontend) (push) Successful in 2m53s
Rust CI / test (1.90.0 / --features ecdsa / no frontend) (push) Successful in 2m51s
Rust CI / test (1.90.0 / --features ecdsa / --features argon2) (push) Successful in 2m57s
Rust CI / test (1.90.0 / --features ecdsa / --features serde) (push) Successful in 3m20s
Rust CI / test (stable / --features ed25519 / no frontend) (push) Successful in 2m54s
Rust CI / test (stable / --features ecdsa / --features argon2) (push) Successful in 3m0s
Rust CI / test (stable / --features ecdsa / --features serde) (push) Successful in 3m19s
Rust CI / test (1.90.0 / --features ed25519 / no frontend) (push) Successful in 2m52s
Rust CI / test (1.90.0 / --features ed25519 / --features argon2) (push) Successful in 2m57s
Rust CI / test (1.90.0 / --features ristretto255 / no frontend) (push) Successful in 3m2s
Rust CI / test (stable / --features ed25519 / --features argon2) (push) Successful in 3m1s
Rust CI / test (1.90.0 / --features ed25519 / --features serde) (push) Successful in 3m20s
Rust CI / test (stable / --features ed25519 / --features serde) (push) Successful in 3m21s
Rust CI / test (stable / --features ristretto255 / no frontend) (push) Successful in 3m4s
Rust CI / test (1.90.0 / --features ristretto255 / --features argon2) (push) Successful in 3m8s
Rust CI / test (1.90.0 / --features ristretto255 / --features serde) (push) Successful in 3m28s
Rust CI / test (stable / --features ristretto255 / --features argon2) (push) Successful in 3m9s
Rust CI / test (stable / --features ristretto255 / --features serde) (push) Successful in 3m32s
Rust CI / test (1.90.0 / --features ristretto255,curve25519,ecdsa,ed25519 / no frontend) (push) Successful in 5m21s
Rust CI / test (stable / --features ristretto255,curve25519,ecdsa,ed25519 / no frontend) (push) Successful in 5m11s
Rust CI / test (1.90.0 / --features ristretto255,curve25519,ecdsa,ed25519 / --features argon2) (push) Successful in 5m27s
Rust CI / test (stable / --features ristretto255,curve25519,ecdsa,ed25519 / --features argon2) (push) Successful in 5m14s
Rust CI / test (stable / --features ristretto255,curve25519,ecdsa,ed25519 / --features serde) (push) Successful in 5m45s
Rust CI / test (1.90.0 / --features ristretto255,curve25519,ecdsa,ed25519 / --features serde) (push) Successful in 5m58s
Rust CI / test (1.90.0 / --features ristretto255,kem / no frontend) (push) Successful in 3m59s
Rust CI / test (stable / --features ristretto255,kem / no frontend) (push) Successful in 4m0s
Rust CI / test (1.90.0 / --features ristretto255,kem / --features argon2) (push) Successful in 4m12s
Rust CI / test (stable / --features ristretto255,kem / --features argon2) (push) Successful in 4m4s
Rust CI / test (1.90.0 / --features ristretto255,kem / --features serde) (push) Successful in 4m34s
Rust CI / test (stable / --features ristretto255,kem / --features serde) (push) Successful in 4m27s
Rust CI / test simple_login example (push) Successful in 18s
Rust CI / test digital_locker example (push) Successful in 19s
Rust CI / cargo bench compilation () (push) Successful in 1m46s
Rust CI / cargo bench compilation (--features ristretto255) (push) Successful in 1m54s
Rust CI / cargo audit (push) Successful in 6s
Rust CI / no-std (wasm32-unknown-unknown / ristretto255,curve25519,ecdsa,ed25519) (push) Successful in 29s
Rust CI / cargo bench compilation (--features ristretto255,kem) (push) Successful in 2m32s
Rust CI / no-std (wasm32-unknown-unknown / no backend) (push) Successful in 28s
Rust CI / no-std (wasm32-unknown-unknown / curve25519) (push) Successful in 18s
Rust CI / no-std (thumbv6m-none-eabi / no backend) (push) Successful in 28s
Rust CI / no-std (thumbv6m-none-eabi / curve25519) (push) Successful in 28s
Rust CI / no-std (wasm32-unknown-unknown / ecdsa) (push) Successful in 18s
Rust CI / no-std (thumbv6m-none-eabi / ecdsa) (push) Successful in 29s
Rust CI / no-std (thumbv6m-none-eabi / ed25519) (push) Successful in 20s
Rust CI / no-std (wasm32-unknown-unknown / ed25519) (push) Successful in 20s
Rust CI / no-std (thumbv6m-none-eabi / ristretto255) (push) Successful in 28s
Rust CI / no-std (wasm32-unknown-unknown / ristretto255) (push) Successful in 27s
Rust CI / no-std (thumbv6m-none-eabi / ristretto255,curve25519,ecdsa,ed25519) (push) Successful in 18s
- Added VexaHub copyright alongside original Meta copyright - Replaced verbose license blocks with SPDX-License-Identifier - Minor code improvements Reviewed-on: #3 Co-authored-by: UneBaguette <[email protected]> Co-committed-by: UneBaguette <[email protected]>
151 lines
4.3 KiB
Rust
151 lines
4.3 KiB
Rust
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
// Copyright (c) VexaHub and contributors.
|
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
|
|
//! Key Exchange group implementation for Curve25519
|
|
|
|
pub use curve25519_dalek;
|
|
use curve25519_dalek::montgomery::MontgomeryPoint;
|
|
use curve25519_dalek::scalar;
|
|
use curve25519_dalek::traits::IsIdentity;
|
|
use generic_array::GenericArray;
|
|
use generic_array::typenum::U32;
|
|
use rand::{CryptoRng, Rng};
|
|
use subtle::ConstantTimeEq;
|
|
use zeroize::ZeroizeOnDrop;
|
|
|
|
use super::Group;
|
|
use crate::errors::{InternalError, ProtocolError};
|
|
use crate::key_exchange::shared::DiffieHellman;
|
|
use crate::serialization::SliceExt;
|
|
|
|
/// Implementation for Curve25519.
|
|
pub struct Curve25519;
|
|
|
|
/// The implementation of such a subgroup for Curve25519
|
|
impl Group for Curve25519 {
|
|
type Pk = NonIdentity;
|
|
type PkLen = U32;
|
|
type Sk = Scalar;
|
|
type SkLen = U32;
|
|
|
|
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen> {
|
|
pk.0.to_bytes().into()
|
|
}
|
|
|
|
fn deserialize_take_pk(bytes: &mut &[u8]) -> Result<Self::Pk, ProtocolError> {
|
|
bytes
|
|
.take_array::<U32>("public key")
|
|
.and_then(|bytes| NonIdentity::from_bytes(bytes.into()))
|
|
}
|
|
|
|
fn random_sk<R: Rng + CryptoRng>(rng: &mut R) -> Self::Sk {
|
|
// Sample 32 random bytes and then clamp, as described in https://cr.yp.to/ecdh.html
|
|
let mut scalar_bytes = [0u8; 32];
|
|
rng.fill_bytes(&mut scalar_bytes);
|
|
let scalar = scalar::clamp_integer(scalar_bytes);
|
|
|
|
Scalar(scalar)
|
|
}
|
|
|
|
fn derive_scalar(seed: GenericArray<u8, Self::SkLen>) -> Result<Self::Sk, InternalError> {
|
|
Ok(Scalar(scalar::clamp_integer(seed.into())))
|
|
}
|
|
|
|
fn public_key(sk: &Self::Sk) -> Self::Pk {
|
|
NonIdentity(MontgomeryPoint::mul_base_clamped(sk.0))
|
|
}
|
|
|
|
fn serialize_sk(sk: &Self::Sk) -> GenericArray<u8, Self::SkLen> {
|
|
sk.0.into()
|
|
}
|
|
|
|
fn deserialize_take_sk(bytes: &mut &[u8]) -> Result<Self::Sk, ProtocolError> {
|
|
bytes
|
|
.take_array::<U32>("secret key")
|
|
.and_then(|bytes| Scalar::from_bytes(bytes.into()))
|
|
}
|
|
}
|
|
|
|
impl DiffieHellman<Curve25519> for Scalar {
|
|
fn diffie_hellman(&self, pk: &NonIdentity) -> GenericArray<u8, U32> {
|
|
Curve25519::serialize_pk(&NonIdentity(pk.0.mul_clamped(self.0)))
|
|
}
|
|
}
|
|
|
|
/// Non-identity point wrapper for [`MontgomeryPoint`].
|
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
|
pub struct NonIdentity(
|
|
#[cfg_attr(feature = "serde", serde(deserialize_with = "serde_deserialize_pk"))]
|
|
MontgomeryPoint,
|
|
);
|
|
|
|
impl NonIdentity {
|
|
fn from_bytes(bytes: [u8; 32]) -> Result<Self, ProtocolError> {
|
|
let point = MontgomeryPoint(bytes);
|
|
|
|
if point.is_identity() {
|
|
Err(ProtocolError::SerializationError)
|
|
} else {
|
|
Ok(NonIdentity(point))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "serde")]
|
|
fn serde_deserialize_pk<'de, D>(deserializer: D) -> Result<MontgomeryPoint, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
use serde::de::{Deserialize, Error};
|
|
|
|
let point = MontgomeryPoint::deserialize(deserializer)?;
|
|
|
|
NonIdentity::from_bytes(point.0)
|
|
.map(|point| point.0)
|
|
.map_err(Error::custom)
|
|
}
|
|
|
|
/// Curve25519 scalar.
|
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
|
#[derive(Clone, Debug, Eq, Hash, PartialEq, ZeroizeOnDrop)]
|
|
pub struct Scalar(
|
|
#[cfg_attr(feature = "serde", serde(deserialize_with = "serde_deserialize_sk"))] [u8; 32],
|
|
);
|
|
|
|
impl Scalar {
|
|
fn from_bytes(bytes: [u8; 32]) -> Result<Self, ProtocolError> {
|
|
let scalar = scalar::clamp_integer(bytes);
|
|
|
|
if scalar.ct_eq(&bytes).into() {
|
|
Ok(Self(scalar))
|
|
} else {
|
|
Err(ProtocolError::SerializationError)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "serde")]
|
|
fn serde_deserialize_sk<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
use serde::de::{Deserialize, Error};
|
|
|
|
Scalar::from_bytes(<[u8; 32]>::deserialize(deserializer)?)
|
|
.map(|scalar| scalar.0)
|
|
.map_err(D::Error::custom)
|
|
}
|
|
|
|
#[test]
|
|
fn non_zero_scalar() {
|
|
use std::vec;
|
|
|
|
use crate::tests::mock_rng::CycleRng;
|
|
|
|
let mut rng = CycleRng::new(vec![0]);
|
|
let sk = Curve25519::random_sk(&mut rng);
|
|
assert_ne!(sk.0, curve25519_dalek::Scalar::ZERO.to_bytes());
|
|
}
|