schnorrkel/
scalars.rs

1// -*- mode: rust; -*-
2//
3// This file is part of schnorrkel.
4// Copyright (c) 2019 Web 3 Foundation
5// See LICENSE for licensing information.
6//
7// Authors:
8// - Jeff Burdges <jeff@web3.foundation>
9
10//! Scalar tooling
11//!
12//! Elliptic curve utilities not provided by curve25519-dalek,
13//! including some not so safe utilities for managing scalars and points.
14
15pub(crate) fn divide_scalar_bytes_by_cofactor(scalar: &mut [u8; 32]) {
16    let mut low = 0u8;
17    for i in scalar.iter_mut().rev() {
18        let r = *i & 0b00000111; // save remainder
19        *i >>= 3; // divide by 8
20        *i += low;
21        low = r << 5;
22    }
23}
24
25pub(crate) fn multiply_scalar_bytes_by_cofactor(scalar: &mut [u8; 32]) {
26    let mut high = 0u8;
27    for i in scalar.iter_mut() {
28        let r = *i & 0b11100000; // carry bits
29        *i <<= 3; // multiply by 8
30        *i += high;
31        high = r >> 5;
32    }
33}
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38    // use ed25519_dalek::SecretKey;
39    use rand::{thread_rng, Rng};
40
41    // TODO: Simple test `RistrettoPoint` is implemented as an `EdwardsPoint`
42    // #[test]
43    // fn ristretto_point_is_edwards_point() {
44    // }
45
46    #[test]
47    fn cofactor_adjustment() {
48        let mut x: [u8; 32] = thread_rng().gen();
49        x[31] &= 0b00011111;
50        let mut y = x.clone();
51        multiply_scalar_bytes_by_cofactor(&mut y);
52        divide_scalar_bytes_by_cofactor(&mut y);
53        assert_eq!(x, y);
54
55        let mut x: [u8; 32] = thread_rng().gen();
56        x[0] &= 0b11111000;
57        let mut y = x.clone();
58        divide_scalar_bytes_by_cofactor(&mut y);
59        multiply_scalar_bytes_by_cofactor(&mut y);
60        assert_eq!(x, y);
61    }
62}