scal3 0.4.1

Verify that systems operate under your sole control (prototype, patent pending)
Documentation
use crate::api::*;
use crate::domain;
use crate::domain::{pk_from_bytes, Result, VerificationError};

pub(crate) mod provider;
pub(crate) mod subscriber;

pub(crate) fn verify(
    verifier: &Verifier,
    pk_device: &Key,
    client_data_hash: &Digest,
    authenticator: &Authenticator,
    proof: &Proof,
    client: &Client
) -> Result {
    let verifier = domain::Verifier::from_bytes(verifier).ok_or(VerificationError)?;
    let pk_device = pk_from_bytes(pk_device).ok_or(VerificationError)?;
    let authenticator = domain::AuthenticatorExtensionTranscript::from_bytes(authenticator).ok_or(VerificationError)?;
    let proof = domain::AuthenticatorProof::from_bytes(proof).ok_or(VerificationError)?;
    let client = domain::ClientExtensionTranscript::from_bytes(client).ok_or(VerificationError)?;
    let transcript = domain::Transcript {
        authenticator,
        proof,
        client,
    };
    verifier.verify_transcript(&transcript, &pk_device, &client_data_hash)
}

#[cfg(test)]
mod tests {
    use crate::api::{Key, Proof, Secret};
    use crate::program::{provider, subscriber, verify};
    use crate::rng::ReproducibleRng;
    use hpke::kem::DhP256HkdfSha256;
    use hpke::{Deserializable, Kem, Serializable};
    use p256::elliptic_curve::sec1::ToEncodedPoint;
    use p256::{ecdsa, NistP256, NonZeroScalar};
    use rand_chacha::rand_core::SeedableRng;
    use signature::hazmat::PrehashSigner;

    fn dh(sk_r: &<DhP256HkdfSha256 as Kem>::PrivateKey, pk_s: &Key) -> Secret {
        let pk_s = p256::PublicKey::from_sec1_bytes(pk_s).unwrap();
        let pk_s = <DhP256HkdfSha256 as Kem>::EncappedKey::from_bytes(
            pk_s.to_encoded_point(false).as_bytes(),
        )
        .unwrap();
        let pk = p256::PublicKey::from_sec1_bytes(&pk_s.to_bytes()).unwrap();
        let sk: NonZeroScalar = NonZeroScalar::from_repr(sk_r.to_bytes()).unwrap();
        let secret = p256::ecdh::diffie_hellman::<NistP256>(sk, pk.as_affine());
        let bytes = secret.raw_secret_bytes().clone();
        bytes.into()
    }

    fn pk(pk_s: &<DhP256HkdfSha256 as Kem>::PublicKey) -> Key {
        let key = p256::PublicKey::from_sec1_bytes(&pk_s.to_bytes()).unwrap();
        key.to_encoded_point(true).as_bytes().try_into().unwrap()
    }

    #[test]
    fn end_to_end_test() {
        let seed = [0u8; 32];
        let mut rng = rand_chacha::ChaCha20Rng::from_seed(seed);

        let (sk_r, pk_r) = DhP256HkdfSha256::gen_keypair(&mut rng);
        let provider: Key = pk(&pk_r);

        let sk_device = ecdsa::SigningKey::random(&mut ReproducibleRng(&mut rng));
        let pk_device = *sk_device.verifying_key();
        let mut arr = [0u8; 33];
        arr.copy_from_slice(&pk_device.to_encoded_point(true).to_bytes());
        let pk_device: Key = arr;

        let mask = [0u8; 32];
        let randomness = [0u8; 32];
        let (subscriber, verifier) = subscriber::register(&mask, &randomness, &provider).unwrap();

        provider::accept(&provider, &dh(&sk_r, &subscriber), &verifier).unwrap();

        let randomness = [1u8; 32];
        let challenge = provider::challenge(&randomness);

        let mask = [0u8; 32];
        let randomness = [2u8; 32];
        let hash = [3u8; 32];
        let (authentication, digest) = subscriber::authenticate(
            &mask,
            &randomness,
            &provider,
            &subscriber,
            &verifier,
            &challenge,
            &hash,
        )
        .unwrap();
        let (signature, _) = sk_device.sign_prehash(&digest).unwrap();
        let mut proof: Proof = [0u8; 64];
        proof.copy_from_slice(&signature.to_bytes());
        let (sender, pass) = subscriber::pass(authentication, &proof).unwrap();

        let randomness = [1u8; 32];
        let (authenticator, proof, client) = provider::prove(
            &randomness,
            &provider,
            &dh(&sk_r, &subscriber),
            &verifier,
            &pk_device,
            &hash,
            &dh(&sk_r, &sender),
            &pass,
        )
        .unwrap();

        assert_eq!(Ok(()), verify(&verifier, &pk_device, &hash, &authenticator, &proof, &client));
    }
}