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
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! `crypto_scalarmult_curve25519` specified in
//! [Cryptography in NaCl](http://nacl.cr.yp.to/valid.html), Sections 2, 3, and 4.
//! This function is conjectured to be strong. For background see Bernstein,
//! "Curve25519: new Diffie-Hellman speed records," Lecture Notes in Computer
//! Science 3958 (2006), 207–228, http://cr.yp.to/papers.html#curve25519.
use ffi;

/// Number of bytes in a `GroupElement`.
pub const GROUPELEMENTBYTES: usize = ffi::crypto_scalarmult_curve25519_BYTES;

/// Number of bytes in a `Scalar`.
pub const SCALARBYTES: usize = ffi::crypto_scalarmult_curve25519_SCALARBYTES;

new_type! {
    /// `Scalar` value (integer in byte representation)
    secret Scalar(SCALARBYTES);
}

new_type! {
    /// `GroupElement`
    secret GroupElement(GROUPELEMENTBYTES);
}

/// `scalarmult()` multiplies a group element `p`
/// by an integer `n`. It returns the resulting group element
/// `Ok(q)`.
/// If the the `GroupElement` is all zero, `scalarmult()` returns `Err(())` since
/// the resulting `GroupElement` would be all zero, no matter the `Scalar`.
pub fn scalarmult(&Scalar(ref n): &Scalar,
                  &GroupElement(ref p): &GroupElement)
                  -> Result<GroupElement, ()> {
    let mut q = [0; GROUPELEMENTBYTES];
    unsafe {
        if ffi::crypto_scalarmult_curve25519(&mut q, n, p) != 0 {
            Err(())
        } else {
            Ok(GroupElement(q))
        }
    }
}

/// `scalarmult_base()` computes the scalar product of a standard
/// group element and an integer `n`. It returns the resulting
/// group element `q`/
pub fn scalarmult_base(&Scalar(ref n): &Scalar) -> GroupElement {
    let mut q = [0; GROUPELEMENTBYTES];
    unsafe {
        ffi::crypto_scalarmult_curve25519_base(&mut q, n);
    }
    GroupElement(q)
}

#[cfg(test)]
mod test {
    use super::*;
    use randombytes::randombytes_into;

    #[test]
    fn test_vector_1() {
        // corresponding to tests/scalarmult.c and tests/scalarmult3.cpp from NaCl
        let alicesk = Scalar([0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1,
                              0x72, 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0,
                              0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a]);
        let alicepk_expected = [0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d,
                                0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38,
                                0x1a, 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a];
        let GroupElement(alicepk) = scalarmult_base(&alicesk);
        assert!(alicepk == alicepk_expected);
    }

    #[test]
    fn test_vector_2() {
        // corresponding to tests/scalarmult2.c and tests/scalarmult4.cpp from NaCl
        let bobsk = Scalar([0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b, 0x79, 0xe1, 0x7f,
                            0x8b, 0x83, 0x80, 0x0e, 0xe6, 0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18,
                            0xb6, 0xfd, 0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb]);
        let bobpk_expected = [0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, 0x61,
                              0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78,
                              0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f];
        let GroupElement(bobpk) = scalarmult_base(&bobsk);
        assert!(bobpk == bobpk_expected);
    }

    #[test]
    fn test_vector_3() {
        // corresponding to tests/scalarmult5.c and tests/scalarmult7.cpp from NaCl
        let alicesk = Scalar([0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1,
                              0x72, 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0,
                              0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a]);
        let bobpk = GroupElement([0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b,
                                  0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8,
                                  0x5b, 0x78, 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88,
                                  0x2b, 0x4f]);
        let k_expected = [0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, 0x72, 0x8e, 0x3b, 0xf4,
                          0x80, 0x35, 0x0f, 0x25, 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33,
                          0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42];
        let GroupElement(k) = scalarmult(&alicesk, &bobpk).unwrap();
        assert!(k == k_expected);
    }

    #[test]
    fn test_vector_4() {
        // corresponding to tests/scalarmult6.c from NaCl
        let bobsk = Scalar([0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b, 0x79, 0xe1, 0x7f,
                            0x8b, 0x83, 0x80, 0x0e, 0xe6, 0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18,
                            0xb6, 0xfd, 0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb]);
        let alicepk = GroupElement([0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b,
                                    0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d,
                                    0x26, 0x38, 0x1a, 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b,
                                    0x4e, 0x6a]);
        let k_expected = [0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, 0x72, 0x8e, 0x3b, 0xf4,
                          0x80, 0x35, 0x0f, 0x25, 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33,
                          0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42];
        let GroupElement(k) = scalarmult(&bobsk, &alicepk).unwrap();
        assert!(k == k_expected);
    }

    #[test]
    #[should_panic]
    fn test_all_zero() {
        let mut sk = [0; SCALARBYTES];
        randombytes_into(&mut sk);
        let sk = Scalar(sk);
        let pk = GroupElement([0; GROUPELEMENTBYTES]);
        let _ = scalarmult(&sk, &pk).unwrap();
    }
}

#[cfg(feature = "benchmarks")]
#[cfg(test)]
mod bench {
    extern crate test;
    use randombytes::randombytes_into;
    use super::*;

    #[bench]
    fn bench_scalarmult(b: &mut test::Bencher) {
        let mut gbs = [0u8; GROUPELEMENTBYTES];
        let mut sbs = [0u8; SCALARBYTES];
        randombytes_into(&mut gbs);
        randombytes_into(&mut sbs);
        let g = GroupElement(gbs);
        let s = Scalar(sbs);
        b.iter(|| {
            scalarmult(&s, &g);
        });
    }

    #[bench]
    fn bench_scalarmult_base(b: &mut test::Bencher) {
        let mut sbs = [0u8; SCALARBYTES];
        randombytes_into(&mut sbs);
        let s = Scalar(sbs);
        b.iter(|| {
            scalarmult_base(&s);
        });
    }
}