wasmsign 0.1.2

Add and verify digital signatures to/from WASM binaries
Documentation
use super::*;
use byteorder::{LittleEndian, WriteBytesExt};
use ed25519_dalek::SIGNATURE_LENGTH;
use rand::rngs::OsRng;
use sha2::{Digest, Sha512};
use std::u32;

const CONTEXT: &[u8] = b"WasmSignature";
pub const ALG_ID: u32 = 0x0000_0001;

pub struct EdDSA;

impl SignatureAlg for EdDSA {
    fn alg_id(&self) -> u32 {
        ALG_ID
    }

    fn raw_signature_length(&self) -> usize {
        SIGNATURE_LENGTH
    }

    fn keygen(&self) -> KeyPair {
        let mut csprng = OsRng::new().expect("CSPRNG not available");
        let keypair = ed25519_dalek::Keypair::generate::<Sha512, _>(&mut csprng);
        KeyPair {
            alg_id: ALG_ID,
            pk: PublicKey::new(ALG_ID, keypair.public.to_bytes().to_vec()),
            sk: SecretKey::new(ALG_ID, keypair.secret.to_bytes().to_vec()),
        }
    }

    fn sign(
        &self,
        data: &[u8],
        ad: Option<&[u8]>,
        key_pair: &KeyPair,
    ) -> Result<Signature, WError> {
        let prehashed = Self::prehash(data, ad)?;
        let xpk = ed25519_dalek::PublicKey::from_bytes(key_pair.pk.raw())?;
        let xsk = ed25519_dalek::SecretKey::from_bytes(key_pair.sk.raw())?;
        let xkey_pair = ed25519_dalek::Keypair {
            public: xpk,
            secret: xsk,
        };
        let raw = xkey_pair
            .sign_prehashed(prehashed, Some(CONTEXT))
            .to_bytes()
            .to_vec();
        Ok(Signature::new(ALG_ID, raw))
    }

    fn verify(
        &self,
        data: &[u8],
        ad: Option<&[u8]>,
        pk: &[u8],
        signature: &Signature,
    ) -> Result<(), WError> {
        assert_eq!(signature.alg_id, ALG_ID);
        let prehashed = Self::prehash(data, ad)?;
        let xpk = ed25519_dalek::PublicKey::from_bytes(pk)?;
        let xsignature = ed25519_dalek::Signature::from_bytes(&signature.raw)?;
        xpk.verify_prehashed(prehashed, Some(CONTEXT), &xsignature)
            .map_err(|e| e.into())
    }
}

impl EdDSA {
    fn prehash(data: &[u8], ad: Option<&[u8]>) -> Result<Sha512, WError> {
        let mut ad_len = vec![];
        let ad = ad.unwrap_or_default();
        if ad.len() > u32::MAX as usize {
            Err(WError::UsageError("Additional data too long"))?
        }
        ad_len.write_u32::<LittleEndian>(ad.len() as u32)?;

        let mut prehashed = Sha512::default();
        prehashed.input(&ad_len);
        prehashed.input(ad);
        prehashed.input(data);

        Ok(prehashed)
    }
}