1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use generic_array::{GenericArray, ArrayLength};
use keystream::SeekableKeyStream;
use rac::{LineValid, Curve};
use crypto_mac::{Mac, NewMac};
use digest::{Update, FixedOutput};

pub trait PseudoRandomStream<T>
where
    T: ArrayLength<u8>,
{
    fn seed(v: GenericArray<u8, T>) -> Self;
}

pub type SharedSecret<A> = GenericArray<u8, <<A as Curve>::Scalar as LineValid>::Length>;

pub trait Sphinx {
    type MacLength: ArrayLength<u8>;
    type AsymmetricKey: Curve;
    type Stream: SeekableKeyStream;

    fn mu<'a, I>(
        shared: &SharedSecret<Self::AsymmetricKey>,
        data: I,
    ) -> GenericArray<u8, Self::MacLength>
    where
        I: Iterator<Item = &'a [u8]>;

    fn rho(shared: &SharedSecret<Self::AsymmetricKey>) -> Self::Stream;

    fn pi(shared: &SharedSecret<Self::AsymmetricKey>) -> Self::Stream;

    fn tau(public_key: Self::AsymmetricKey) -> SharedSecret<Self::AsymmetricKey>;

    fn blinding(
        public_key: &Self::AsymmetricKey,
        shared: &SharedSecret<Self::AsymmetricKey>,
    ) -> <Self::AsymmetricKey as Curve>::Scalar;
}

impl<A, C, D, S> Sphinx for (A, C, D, S)
where
    A: Curve,
    C: Mac + NewMac,
    D: Default + Update + FixedOutput<OutputSize = <<A as Curve>::Scalar as LineValid>::Length>,
    S: PseudoRandomStream<C::OutputSize> + SeekableKeyStream,
{
    type MacLength = C::OutputSize;
    type AsymmetricKey = A;
    type Stream = S;

    fn mu<'a, I>(
        shared: &SharedSecret<Self::AsymmetricKey>,
        data: I,
    ) -> GenericArray<u8, Self::MacLength>
    where
        I: Iterator<Item = &'a [u8]>,
    {
        let mut collector = C::new_varkey(b"mu").unwrap();
        collector.update(shared);
        let key = collector.finalize().into_bytes();
        let mut collector = C::new_varkey(&key).unwrap();
        data.for_each(|s| collector.update(s));
        collector.finalize().into_bytes()
    }

    fn rho(shared: &SharedSecret<Self::AsymmetricKey>) -> Self::Stream {
        let mut collector = C::new_varkey(b"rho").unwrap();
        collector.update(shared);
        let key = collector.finalize().into_bytes();
        S::seed(key)
    }

    fn pi(shared: &SharedSecret<Self::AsymmetricKey>) -> Self::Stream {
        let mut collector = C::new_varkey(b"um").unwrap();
        collector.update(shared);
        let key = collector.finalize().into_bytes();
        S::seed(key)
    }

    fn tau(public_key: Self::AsymmetricKey) -> SharedSecret<Self::AsymmetricKey> {
        D::default()
            .chain(public_key.compress().clone_line().as_ref())
            .finalize_fixed()
    }

    fn blinding(
        public_key: &Self::AsymmetricKey,
        shared: &SharedSecret<Self::AsymmetricKey>,
    ) -> <Self::AsymmetricKey as Curve>::Scalar {
        let r = D::default()
            .chain(public_key.compress().clone_line().as_ref())
            .chain(shared)
            .finalize_fixed();
        // safe to unwrap because array is result if hashing
        LineValid::try_clone_array(&r).unwrap()
    }
}