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};
pub struct BlindRequest {
u: Scalar,
v: Scalar,
r: RistrettoPoint,
e: Scalar,
}
impl BlindRequest {
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())
}
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)
}
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))
}
}
#[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()?;
let rp = CompressedRistretto(*rp)
.decompress()
.ok_or(WiredRistrettoPointMalformed)?;
let u = Scalar::random(&mut rng);
let v = Scalar::random(&mut rng);
let r = generate_r(u, v, rp);
let e = generate_e::<H>(r, m.as_ref());
let ep = generate_ep(u, e);
Ok((ep.to_bytes(), BlindRequest { u, v, r, e }))
}
fn generate_r(u: Scalar, v: Scalar, rp: RistrettoPoint) -> RistrettoPoint {
u * rp + v * RISTRETTO_BASEPOINT_POINT
}
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)
}
fn generate_ep(u: Scalar, e: Scalar) -> Scalar {
u.invert() * e
}