src/non_reducing_scalar52.rs (88 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the APACHE 2.0 license found in
// the LICENSE file in the root directory of this source tree.
use core::ops::{Index, IndexMut};
/// The `Scalar52` struct represents an element in
/// ℤ/ℓℤ as 5 52-bit limbs.
pub struct Scalar52(pub [u64; 5]);
/// `L` is the order of base point, i.e. 2^252 + 27742317777372353535851937790883648493
pub const L: Scalar52 = Scalar52([
0x0002_631a_5cf5_d3ed,
0x000d_ea2f_79cd_6581,
0x0000_0000_0014_def9,
0x0000_0000_0000_0000,
0x0000_1000_0000_0000,
]);
impl Scalar52 {
/// Return the zero scalar
pub fn zero() -> Scalar52 {
Scalar52([0, 0, 0, 0, 0])
}
/// Unpack a 32 byte / 256 bit scalar into 5 52-bit limbs.
pub fn from_bytes(bytes: &[u8; 32]) -> Scalar52 {
let mut words = [0u64; 4];
for i in 0..4 {
for j in 0..8 {
words[i] |= u64::from(bytes[(i * 8) + j]) << (j * 8) as u64;
}
}
let mask = (1u64 << 52) - 1;
let top_mask = (1u64 << 48) - 1;
let mut s = Scalar52::zero();
s[0] = words[0] & mask;
s[1] = ((words[0] >> 52) | (words[1] << 12)) & mask;
s[2] = ((words[1] >> 40) | (words[2] << 24)) & mask;
s[3] = ((words[2] >> 28) | (words[3] << 36)) & mask;
s[4] = (words[3] >> 16) & top_mask;
s
}
/// Pack the limbs of this `Scalar52` into 32 bytes
pub fn to_bytes(&self) -> [u8; 32] {
let mut s = [0u8; 32];
s[0] = self.0[0] as u8;
s[1] = (self.0[0] >> 8) as u8;
s[2] = (self.0[0] >> 16) as u8;
s[3] = (self.0[0] >> 24) as u8;
s[4] = (self.0[0] >> 32) as u8;
s[5] = (self.0[0] >> 40) as u8;
s[6] = ((self.0[0] >> 48) | (self.0[1] << 4)) as u8;
s[7] = (self.0[1] >> 4) as u8;
s[8] = (self.0[1] >> 12) as u8;
s[9] = (self.0[1] >> 20) as u8;
s[10] = (self.0[1] >> 28) as u8;
s[11] = (self.0[1] >> 36) as u8;
s[12] = (self.0[1] >> 44) as u8;
s[13] = self.0[2] as u8;
s[14] = (self.0[2] >> 8) as u8;
s[15] = (self.0[2] >> 16) as u8;
s[16] = (self.0[2] >> 24) as u8;
s[17] = (self.0[2] >> 32) as u8;
s[18] = (self.0[2] >> 40) as u8;
s[19] = ((self.0[2] >> 48) | (self.0[3] << 4)) as u8;
s[20] = (self.0[3] >> 4) as u8;
s[21] = (self.0[3] >> 12) as u8;
s[22] = (self.0[3] >> 20) as u8;
s[23] = (self.0[3] >> 28) as u8;
s[24] = (self.0[3] >> 36) as u8;
s[25] = (self.0[3] >> 44) as u8;
s[26] = self.0[4] as u8;
s[27] = (self.0[4] >> 8) as u8;
s[28] = (self.0[4] >> 16) as u8;
s[29] = (self.0[4] >> 24) as u8;
s[30] = (self.0[4] >> 32) as u8;
s[31] = (self.0[4] >> 40) as u8;
s
}
/// Compute `a + b` (without mod ℓ)
pub fn add(a: &Scalar52, b: &Scalar52) -> Scalar52 {
let mut sum = Scalar52::zero();
let mask = (1u64 << 52) - 1;
// a + b
let mut carry: u64 = 0;
for i in 0..5 {
carry = a[i] + b[i] + (carry >> 52);
sum[i] = carry & mask;
}
sum
}
}
impl Index<usize> for Scalar52 {
type Output = u64;
fn index(&self, _index: usize) -> &u64 {
&(self.0[_index])
}
}
impl IndexMut<usize> for Scalar52 {
fn index_mut(&mut self, _index: usize) -> &mut u64 {
&mut (self.0[_index])
}
}