blindsign 0.0.6

A package for creating blind signatures cryptography ECC
Documentation
//! Requester side of the protocol
//!
//! # Note
//!
//! This **does not** include **any** networking code, such as any code to
//! actually request protocol initiation. Also, the request for protocol
//! initiation is neither defined nor implemented by this crate.
use curve25519_dalek::{
    constants::RISTRETTO_BASEPOINT_POINT,
    ristretto::{CompressedRistretto, RistrettoPoint},
    scalar::Scalar,
};
use digest::Digest;
use rand::OsRng;
use signature::UnblindedSigData;
use typenum::U64;
use Error::{WiredRistrettoPointMalformed, WiredScalarMalformed};

/// For managing the requester steps of the blind signature protocol. Actually
/// initiating the protocol such that the signer knows to begin the first step
/// (generating R') is orthogonal to this crate.
pub struct BlindRequest {
    u: Scalar,
    v: Scalar,
    r: RistrettoPoint,
    e: Scalar,
}

impl BlindRequest {
    /// Perform the first set of requester side steps toward acquiring a blindly
    /// signed message. Generates a random 32 byte scalar to use as the message,
    /// seeing as it is uncommon to need any particular message to be blindly
    /// signed.
    ///
    /// # Arguments
    ///
    /// * 'rp' - A reference to a 32 byte CompressedRistrettoPoint represented
    /// as a [u8; 32]. This is the R' value received from the siger in response
    /// to a request for protocol initiation, though how it is requested or
    /// received is orthogonal to this crate.
    ///
    /// # Type Paramaeters
    ///
    /// H is the hash algorithm that will be used for generating e
    ///
    /// # Returns
    ///
    /// * Ok(([u8; 32], BlindRequest)) on success. The [u8; 32] represents the
    /// value e', which is sent to the server for blind signing.
    ///
    /// * Err(::Error) variant on error, which could be caused by the failure to
    /// initiate the RNG, or otherwise being input a malformed R' value from the
    /// signer.
    ///
    /// # Mathematics
    ///
    /// * R = u*R' + v*P
    /// * u = Randomly Generated Scalar by requester
    /// * v = Randomly Generated Scalar by requester
    /// _____
    /// * e = H(R||m)
    /// * H() = A hash function producing 64 byte outputs
    /// * m = The bytes of the message to be blindly signed
    /// _____
    /// * e' = e / u
    pub fn new<H>(rp: &[u8; 32]) -> ::Result<([u8; 32], Self)>
    where
        H: Digest<OutputSize = U64> + Default,
    {
        initiate::<H, &[u8; 32]>(rp, Scalar::random(&mut OsRng::new()?).as_bytes())
    }

    /// The same as new, but allows for passing in a specific message value 'm'
    /// to be blindly signed.
    pub fn new_specific_msg<H, M>(rp: &[u8; 32], m: M) -> ::Result<([u8; 32], Self)>
    where
        H: Digest<OutputSize = U64> + Default,
        M: AsRef<[u8]>,
    {
        initiate::<H, M>(rp, m)
    }

    /// Input the blinded signature S' from the signer, consumes self and
    /// creates the complete blindly signed message structure. Note that this
    /// method does not actually verify that a correct sp value was received
    /// from the signer, only that it was a valid canonical scalar.
    ///
    /// # Arguments
    ///
    /// * 'sp' - A reference to a 32 byte Scalar represented as a [u8; 32]. This
    /// scalar is received from the signer and is the signature on the value e'.
    ///
    /// # Returns
    ///
    /// * Ok(UnblindedSigData) on success. The UnblindedSigData consists of
    ///
    /// 1. The unblinded S' value = **S**, the signature (on unblinded e' value, which is e = H(msg||R))
    /// 2. The **e** value (which is the unblinded e' value, on which S is the signature)
    /// 3. The **R** value (which is the unblinded R' value that was originally received from the signer)
    ///
    /// * Err(::Error) on error. The only error is if the input sp is not a
    /// valid scalar. Note that this method **does not** actually ensure that
    /// the signature is valid, only that the scalar of the signature is
    /// correctly formed.
    ///
    /// # Mathematics
    ///
    /// * S = S' * u + v
    /// * v = Random scalar previously generated by requester
    /// * u = Random scalar previously generated by requester
    pub fn gen_signed_msg(self, sp: &[u8; 32]) -> ::Result<UnblindedSigData> {
        let sp = Scalar::from_canonical_bytes(*sp).ok_or(WiredScalarMalformed)?;
        Ok(UnblindedSigData::new(self.e, sp * self.u + self.v, self.r))
    }
}

// Implementation internal functions, not exposed to crate users -->

/// Internal code for all new variants (ie: with random or specific msg)
#[allow(many_single_char_names)]
fn initiate<H, M>(rp: &[u8; 32], m: M) -> ::Result<([u8; 32], BlindRequest)>
where
    H: Digest<OutputSize = U64> + Default,
    M: AsRef<[u8]>,
{
    let mut rng = OsRng::new()?;
    // Load the wired R' value into RistrettoPoint form, error if the wired
    // form was malformed.
    let rp = CompressedRistretto(*rp)
        .decompress()
        .ok_or(WiredRistrettoPointMalformed)?;

    // The random scalars u and v must be generated
    let u = Scalar::random(&mut rng);
    let v = Scalar::random(&mut rng);

    // R = u*R' + v*P
    let r = generate_r(u, v, rp);

    // e = H(R||m)
    let e = generate_e::<H>(r, m.as_ref());

    // e' = e / u
    let ep = generate_ep(u, e);

    Ok((ep.to_bytes(), BlindRequest { u, v, r, e }))
}

/// The requester, given R' from the signer, calculates R = u*R' + v*P, where
/// * u = a randomly chosen number by the requester
/// * v = a randomly chosen number by the requester
/// * P = a generator point in ECC
fn generate_r(u: Scalar, v: Scalar, rp: RistrettoPoint) -> RistrettoPoint {
    u * rp + v * RISTRETTO_BASEPOINT_POINT
}

/// The requester generates e = H(R||m), where
/// * H() = a hash function producing 64 byte outputs
/// * R = the previously calculated R value
/// * m = the message to be  signed
///
/// pub(crate) as used in signature.rs
pub(crate) fn generate_e<H>(r: RistrettoPoint, m: &[u8]) -> Scalar
where
    H: Digest<OutputSize = U64> + Default,
{
    let mut hasher = H::default();
    hasher.input(r.compress().as_bytes());
    hasher.input(m);
    Scalar::from_hash(hasher)
}

/// The requester calculates e' = e / u, where
/// * e = the previously generated e value
/// * u = a randomly chosen number by the requester
fn generate_ep(u: Scalar, e: Scalar) -> Scalar {
    u.invert() * e
}