use crate::crypto::{Random32Bytes, Signature, VerifyingKey};
use crate::errors::CryptoError;
use crate::traits::IdentityProvider;
use crate::{crypto, utils};
pub fn initiate() -> Random32Bytes {
Random32Bytes::generate()
}
pub fn respond(
challenge_fragments: &[Random32Bytes],
identity_provider: &impl IdentityProvider,
) -> Signature {
identity_provider.sign(&challenge_message_bytes(challenge_fragments))
}
pub fn verify(
signature: &Signature,
challenge_fragments: &[Random32Bytes],
verifying_key: &VerifyingKey,
) -> Result<(), CryptoError> {
crypto::verify_signature(
verifying_key,
&challenge_message_bytes(challenge_fragments),
signature,
)
}
fn challenge_message_bytes(challenge_fragments: &[Random32Bytes]) -> Vec<u8> {
let mut sorted_challenge_fragments = challenge_fragments.to_owned();
sorted_challenge_fragments.sort();
utils::prefix_message_bytes(&sorted_challenge_fragments.iter().fold(
Vec::<u8>::new(),
|mut acc, n| {
acc.append(&mut n.to_be_bytes().to_vec());
acc
},
))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::MockECDSAIdentityProvider;
use crypto_bigint::U256;
#[test]
fn identity_challenge_works() {
let identity_provider = MockECDSAIdentityProvider::generate();
let challenge_fragments: Vec<Random32Bytes> = (0..5).map(|_| initiate()).collect();
for (actual_signer, fragments_to_sign, fragments_to_verify, expected_result) in [
(
&identity_provider,
&challenge_fragments,
&challenge_fragments,
Ok(()),
),
(
&MockECDSAIdentityProvider::generate(),
&challenge_fragments,
&challenge_fragments,
Err(CryptoError::InvalidSignature),
),
(
&identity_provider,
&(0..3u8)
.map(|n| Random32Bytes::from(U256::from(n)))
.collect(),
&challenge_fragments,
Err(CryptoError::InvalidSignature),
),
] {
let challenge_response = respond(fragments_to_sign, actual_signer);
let result = verify(
&challenge_response,
fragments_to_verify,
&identity_provider.verifying_key(),
);
assert_eq!(result, expected_result);
}
}
}