Dependency Hell with `kyberlib`

โš“ rust    ๐Ÿ“… 2025-05-07    ๐Ÿ‘ค surdeus    ๐Ÿ‘๏ธ 5      

surdeus

Warning

This post was published 55 days ago. The information described in this article may have changed.

I'm trying to use the crate kyberlib to implement quantum-resistant key exchange (for a school project). Unfortunately, cargo doesn't like something about the traits implemented by my CSPRNG (ChaCha20):

the trait bound `ChaCha20Rng: kyberlib::RngCore` is not satisfied
two types coming from two different versions of the same crate are different types even if they look the same
you can use `cargo tree` to explore your dependency treerustcClick for full compiler diagnostic
qsh_kyberlib.rs(41, 26): required by a bound introduced by this call
lib.rs(142, 1): there are multiple different versions of crate `rand_core` in the dependency graph
api.rs(37, 8): required by a bound in `kyberlib::keypair`
the trait bound `ChaCha20Rng: kyberlib::CryptoRng` is not satisfied
two types coming from two different versions of the same crate are different types even if they look the same
you can use `cargo tree` to explore your dependency treerustcClick for full compiler diagnostic
qsh_kyberlib.rs(41, 26): required by a bound introduced by this call
lib.rs(209, 1): there are multiple different versions of crate `rand_core` in the dependency graph
api.rs(37, 18): required by a bound in `kyberlib::keypair`

I have little idea what's going on, and I need this solved ASAP.
It seems that the maintainer wrote his own RandCore and CryptoRng..?

Code:

/*!
	Implements the default key exchange method, kyberlib (CRYSTALS-Kyber).
	Key exchange method 0.
*/

use std::array::TryFromSliceError;

// External dependancies go here:
use rand_chacha::ChaCha20Rng;
use rand_chacha::rand_core::SeedableRng;
use kyberlib::{keypair, Ake, AkeSendInit, AkeSendResponse, Keypair, KyberLibError, PublicKey};

// Internal dependancies go here:
use super::KeyExchanger;


pub struct KyberlibKeyExchanger {

	// Generator for random numbers:
	random: ChaCha20Rng,

	// Stores the state for the key exchange:
	state: Ake,

	// Stores the keypair for this exchange:
	keypair: Keypair,

	// Stores the public key of the remote host:
	remote_pubkey: Option<PublicKey>,

}

impl KeyExchanger for KyberlibKeyExchanger {
	type Error = KyberLibError;
	type ClientInit = AkeSendInit;
	type ServerInit = AkeSendResponse;

	fn new() -> Result<Self, Self::Error> {
		let mut random: ChaCha20Rng = ChaCha20Rng::from_os_rng();
		let state: Ake = Ake::new();
		let keypair: Keypair = keypair(&mut random)?;

		return Ok(Self {
			random: random,
			state: state,
			keypair: keypair,
			remote_pubkey: None,
		});
	}
	
	fn get_local_pubkey(&self) -> &[u8] {
		return &self.keypair.public;
	}

	fn set_remote_pubkey(&mut self, pubkey: &[u8]) -> Result<(), TryFromSliceError> {
		self.remote_pubkey = Some(PublicKey::from(pubkey.try_into()?));
		return Ok(());
	}

	fn client_init(&mut self) -> Result<Self::ClientInit, Self::Error> {
		// Check if there's a public key stored here yet:
		if let Some(pubkey) = self.remote_pubkey {
			// If there is, run `client_init`, propagate any errors, and return the data as an owned Vec:
			return Ok(self.state.client_init(&pubkey, &mut self.random)?);
		} else {
			// Or return this error (`MissingKey` would be more appropriate, but that doesn't exist๐Ÿ˜):
			return Err(KyberLibError::InvalidKey);
		}
	}

	fn server_init(&mut self, client_init: Self::ClientInit) -> Result<Self::ServerInit, Self::Error> {
		// Check if there's a public key:
		if let Some(pubkey) = self.remote_pubkey {
			// If yes, `server_init`:
			return Ok(self.state.server_receive(client_init, &pubkey, &self.keypair.secret, &mut self.random)?);
		} else {
			// If not, error:
			return Err(KyberLibError::InvalidKey);
		}
	}

	fn client_confirm(&mut self, server_init: Self::ServerInit) -> Result<(), Self::Error> {
		// Final step: propagate errors:
		self.state.client_confirm(server_init, &self.keypair.secret)?;
		// Or return `Ok`:
		return Ok(());
	}

	fn shared_secret(&self) -> &[u8] {
		return &self.state.shared_secret;
	}

}

#[test]
fn test_kyberlib_key_exchanger() {
	//let key_exchanger: KyberlibKeyExchanger = KyberlibKeyExchanger::new().expect("Failed to instantiate a `KyberlibKeyExchanger`");	// I know, not really a key. But what was I supposed to do? This is testing functionality, not security...
	todo!()	// Add the rest of the test, once we have the rest of the features.
}

6 posts - 4 participants

Read full topic

๐Ÿท๏ธ rust_feed