Initial commit
This commit is contained in:
541
libraries/crypto/src/aes256.rs
Normal file
541
libraries/crypto/src/aes256.rs
Normal file
@@ -0,0 +1,541 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::util::{xor_block_16, Block16};
|
||||
use super::{Decrypt16BytesBlock, Encrypt16BytesBlock};
|
||||
|
||||
/** A portable and naive textbook implementation of AES-256 **/
|
||||
type Word = [u8; 4];
|
||||
|
||||
/** This structure caches the round keys, to avoid re-computing the key schedule for each block. **/
|
||||
pub struct EncryptionKey {
|
||||
enc_round_keys: [Block16; 15],
|
||||
}
|
||||
|
||||
pub struct DecryptionKey {
|
||||
dec_round_keys: [Block16; 15],
|
||||
}
|
||||
|
||||
impl EncryptionKey {
|
||||
// Computes the round keys.
|
||||
pub fn new(key: &[u8; 32]) -> EncryptionKey {
|
||||
let mut enc_round_keys = [Default::default(); 15];
|
||||
|
||||
enc_round_keys[0] = *array_ref![key, 0, 16];
|
||||
enc_round_keys[1] = *array_ref![key, 16, 16];
|
||||
|
||||
let mut word: Word = *array_ref![enc_round_keys[1], 12, 4];
|
||||
for i in 2..15 {
|
||||
if i & 1 == 0 {
|
||||
rotword(&mut word);
|
||||
subword(&mut word);
|
||||
word[0] ^= RCON[(i >> 1) - 1];
|
||||
} else {
|
||||
subword(&mut word);
|
||||
}
|
||||
|
||||
for j in 0..4 {
|
||||
xorword(&mut word, *array_ref![enc_round_keys[i - 2], 4 * j, 4]);
|
||||
*array_mut_ref![enc_round_keys[i], 4 * j, 4] = word;
|
||||
}
|
||||
}
|
||||
|
||||
EncryptionKey { enc_round_keys }
|
||||
}
|
||||
}
|
||||
|
||||
impl Encrypt16BytesBlock for EncryptionKey {
|
||||
// Encrypt an AES block in place.
|
||||
fn encrypt_block(&self, block: &mut Block16) {
|
||||
add_round_key(block, &self.enc_round_keys[0]);
|
||||
for i in 1..14 {
|
||||
aes_enc(block, &self.enc_round_keys[i]);
|
||||
}
|
||||
aes_enc_last(block, &self.enc_round_keys[14]);
|
||||
}
|
||||
}
|
||||
|
||||
impl DecryptionKey {
|
||||
// Computes the round keys.
|
||||
pub fn new(key: &EncryptionKey) -> DecryptionKey {
|
||||
let mut dec_round_keys = [Default::default(); 15];
|
||||
dec_round_keys[0] = key.enc_round_keys[14];
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for i in 1..14 {
|
||||
let rk = &mut dec_round_keys[i];
|
||||
*rk = key.enc_round_keys[14 - i];
|
||||
inv_mix_columns(rk);
|
||||
}
|
||||
dec_round_keys[14] = key.enc_round_keys[0];
|
||||
|
||||
DecryptionKey { dec_round_keys }
|
||||
}
|
||||
}
|
||||
|
||||
impl Decrypt16BytesBlock for DecryptionKey {
|
||||
// Decrypt an AES block in place.
|
||||
fn decrypt_block(&self, block: &mut Block16) {
|
||||
add_round_key(block, &self.dec_round_keys[0]);
|
||||
for i in 1..14 {
|
||||
aes_dec(block, &self.dec_round_keys[i]);
|
||||
}
|
||||
aes_dec_last(block, &self.dec_round_keys[14]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Helper functions for the key schedule **/
|
||||
fn rotword(word: &mut Word) {
|
||||
let tmp = word[0];
|
||||
word[0] = word[1];
|
||||
word[1] = word[2];
|
||||
word[2] = word[3];
|
||||
word[3] = tmp;
|
||||
}
|
||||
|
||||
fn subword(word: &mut Word) {
|
||||
for byte in word.iter_mut() {
|
||||
*byte = SBOX[*byte as usize];
|
||||
}
|
||||
}
|
||||
|
||||
fn xorword(word: &mut Word, src: Word) {
|
||||
for i in 0..4 {
|
||||
word[i] ^= src[i];
|
||||
}
|
||||
}
|
||||
|
||||
/** Helper functions for the encryption **/
|
||||
fn aes_enc(block: &mut Block16, rkey: &Block16) {
|
||||
sub_bytes(block);
|
||||
shift_rows(block);
|
||||
mix_columns(block);
|
||||
add_round_key(block, rkey);
|
||||
}
|
||||
|
||||
fn aes_dec(block: &mut Block16, rkey: &Block16) {
|
||||
inv_shift_rows(block);
|
||||
inv_sub_bytes(block);
|
||||
inv_mix_columns(block);
|
||||
add_round_key(block, rkey);
|
||||
}
|
||||
|
||||
fn aes_enc_last(block: &mut Block16, rkey: &Block16) {
|
||||
sub_bytes(block);
|
||||
shift_rows(block);
|
||||
add_round_key(block, rkey);
|
||||
}
|
||||
|
||||
fn aes_dec_last(block: &mut Block16, rkey: &Block16) {
|
||||
inv_shift_rows(block);
|
||||
inv_sub_bytes(block);
|
||||
add_round_key(block, rkey);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn add_round_key(block: &mut Block16, rkey: &Block16) {
|
||||
xor_block_16(block, rkey);
|
||||
}
|
||||
|
||||
fn sub_bytes(block: &mut Block16) {
|
||||
for byte in block.iter_mut() {
|
||||
*byte = SBOX[*byte as usize];
|
||||
}
|
||||
}
|
||||
|
||||
fn inv_sub_bytes(block: &mut Block16) {
|
||||
for byte in block.iter_mut() {
|
||||
*byte = SBOX_INV[*byte as usize];
|
||||
}
|
||||
}
|
||||
|
||||
fn shift_rows(block: &mut Block16) {
|
||||
let tmp = block[1];
|
||||
block[1] = block[5];
|
||||
block[5] = block[9];
|
||||
block[9] = block[13];
|
||||
block[13] = tmp;
|
||||
|
||||
block.swap(2, 10);
|
||||
block.swap(6, 14);
|
||||
|
||||
let tmp = block[3];
|
||||
block[3] = block[15];
|
||||
block[15] = block[11];
|
||||
block[11] = block[7];
|
||||
block[7] = tmp;
|
||||
}
|
||||
|
||||
fn inv_shift_rows(block: &mut Block16) {
|
||||
let tmp = block[7];
|
||||
block[7] = block[11];
|
||||
block[11] = block[15];
|
||||
block[15] = block[3];
|
||||
block[3] = tmp;
|
||||
|
||||
block.swap(2, 10);
|
||||
block.swap(6, 14);
|
||||
|
||||
let tmp = block[13];
|
||||
block[13] = block[9];
|
||||
block[9] = block[5];
|
||||
block[5] = block[1];
|
||||
block[1] = tmp;
|
||||
}
|
||||
|
||||
// multiplication by 2 in GF(2^256)
|
||||
fn mul2(x: u8) -> u8 {
|
||||
(x << 1) ^ (((x >> 7) & 1) * 0x1b)
|
||||
}
|
||||
|
||||
// multiplication by 3 in GF(2^256)
|
||||
fn mul3(x: u8) -> u8 {
|
||||
mul2(x) ^ x
|
||||
}
|
||||
|
||||
fn mix_columns(block: &mut Block16) {
|
||||
for i in 0..4 {
|
||||
let x0 = block[4 * i];
|
||||
let x1 = block[4 * i + 1];
|
||||
let x2 = block[4 * i + 2];
|
||||
let x3 = block[4 * i + 3];
|
||||
block[4 * i] = mul2(x0) ^ mul3(x1) ^ x2 ^ x3;
|
||||
block[4 * i + 1] = x0 ^ mul2(x1) ^ mul3(x2) ^ x3;
|
||||
block[4 * i + 2] = x0 ^ x1 ^ mul2(x2) ^ mul3(x3);
|
||||
block[4 * i + 3] = mul3(x0) ^ x1 ^ x2 ^ mul2(x3);
|
||||
}
|
||||
}
|
||||
|
||||
// multiplication by 9 in GF(2^256)
|
||||
fn mul9(x: u8) -> u8 {
|
||||
mul2(mul2(mul2(x))) ^ x
|
||||
}
|
||||
|
||||
// multiplication by 11 in GF(2^256)
|
||||
fn mul11(x: u8) -> u8 {
|
||||
mul2(mul2(mul2(x)) ^ x) ^ x
|
||||
}
|
||||
|
||||
// multiplication by 13 in GF(2^256)
|
||||
fn mul13(x: u8) -> u8 {
|
||||
mul2(mul2(mul2(x) ^ x)) ^ x
|
||||
}
|
||||
|
||||
// multiplication by 14 in GF(2^256)
|
||||
fn mul14(x: u8) -> u8 {
|
||||
mul2(mul2(mul2(x) ^ x) ^ x)
|
||||
}
|
||||
|
||||
fn inv_mix_columns(block: &mut Block16) {
|
||||
for i in 0..4 {
|
||||
let x0 = block[4 * i];
|
||||
let x1 = block[4 * i + 1];
|
||||
let x2 = block[4 * i + 2];
|
||||
let x3 = block[4 * i + 3];
|
||||
block[4 * i] = mul14(x0) ^ mul11(x1) ^ mul13(x2) ^ mul9(x3);
|
||||
block[4 * i + 1] = mul9(x0) ^ mul14(x1) ^ mul11(x2) ^ mul13(x3);
|
||||
block[4 * i + 2] = mul13(x0) ^ mul9(x1) ^ mul14(x2) ^ mul11(x3);
|
||||
block[4 * i + 3] = mul11(x0) ^ mul13(x1) ^ mul9(x2) ^ mul14(x3);
|
||||
}
|
||||
}
|
||||
|
||||
/** Constants **/
|
||||
// Constants used in the key schedule.
|
||||
const RCON: [u8; 7] = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40];
|
||||
|
||||
// AES substitution box.
|
||||
const SBOX: [u8; 256] = [
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
|
||||
];
|
||||
|
||||
const SBOX_INV: [u8; 256] = [
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
|
||||
];
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
// Test vector from the NIST obtained at:
|
||||
// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_ECB.pdf
|
||||
#[test]
|
||||
fn test_nist_aes256_ecb_encrypt() {
|
||||
let src = b"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\
|
||||
\xe9\x3d\x7e\x11\x73\x93\x17\x2a";
|
||||
let key = b"\x60\x3d\xeb\x10\x15\xca\x71\xbe\
|
||||
\x2b\x73\xae\xf0\x85\x7d\x77\x81\
|
||||
\x1f\x35\x2c\x07\x3b\x61\x08\xd7\
|
||||
\x2d\x98\x10\xa3\x09\x14\xdf\xf4";
|
||||
let expected = b"\xf3\xee\xd1\xbd\xb5\xd2\xa0\x3c\
|
||||
\x06\x4b\x5a\x7e\x3d\xb1\x81\xf8";
|
||||
|
||||
let mut dst: Block16 = Default::default();
|
||||
dst.copy_from_slice(src);
|
||||
EncryptionKey::new(key).encrypt_block(&mut dst);
|
||||
assert_eq!(&dst, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nist_aes256_ecb_decrypt() {
|
||||
let src = b"\xf3\xee\xd1\xbd\xb5\xd2\xa0\x3c\
|
||||
\x06\x4b\x5a\x7e\x3d\xb1\x81\xf8";
|
||||
let key = b"\x60\x3d\xeb\x10\x15\xca\x71\xbe\
|
||||
\x2b\x73\xae\xf0\x85\x7d\x77\x81\
|
||||
\x1f\x35\x2c\x07\x3b\x61\x08\xd7\
|
||||
\x2d\x98\x10\xa3\x09\x14\xdf\xf4";
|
||||
let expected = b"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\
|
||||
\xe9\x3d\x7e\x11\x73\x93\x17\x2a";
|
||||
|
||||
let mut dst: Block16 = Default::default();
|
||||
dst.copy_from_slice(src);
|
||||
DecryptionKey::new(&EncryptionKey::new(key)).decrypt_block(&mut dst);
|
||||
assert_eq!(&dst, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encrypt_decrypt() {
|
||||
// Test that decrypt_block is the inverse of encrypt_block for a bunch of block values.
|
||||
let key_bytes = b"\x60\x3d\xeb\x10\x15\xca\x71\xbe\
|
||||
\x2b\x73\xae\xf0\x85\x7d\x77\x81\
|
||||
\x1f\x35\x2c\x07\x3b\x61\x08\xd7\
|
||||
\x2d\x98\x10\xa3\x09\x14\xdf\xf4";
|
||||
let enc_key = EncryptionKey::new(key_bytes);
|
||||
let dec_key = DecryptionKey::new(&enc_key);
|
||||
let mut block: Block16 = [0; 16];
|
||||
for i in 0..=255 {
|
||||
for j in 0..16 {
|
||||
block[j] = (i + j) as u8;
|
||||
}
|
||||
let expected = block;
|
||||
enc_key.encrypt_block(&mut block);
|
||||
dec_key.decrypt_block(&mut block);
|
||||
assert_eq!(block, expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sbox_is_permutation() {
|
||||
let mut image = [false; 256];
|
||||
for &sboxed in SBOX.iter() {
|
||||
assert_eq!(image[sboxed as usize], false);
|
||||
image[sboxed as usize] = true;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sbox_inv_is_permutation() {
|
||||
let mut image = [false; 256];
|
||||
for &sboxed in SBOX_INV.iter() {
|
||||
assert_eq!(image[sboxed as usize], false);
|
||||
image[sboxed as usize] = true;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sbox_inverse() {
|
||||
for i in 0..=255 {
|
||||
assert_eq!(SBOX_INV[SBOX[i as usize] as usize], i);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_subbytes() {
|
||||
let mut block = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
let expected = [
|
||||
99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
|
||||
];
|
||||
sub_bytes(&mut block);
|
||||
assert_eq!(block, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_subbytes_inv() {
|
||||
// Test that inv_sub_bytes is the inverse of sub_bytes for a bunch of block values.
|
||||
let mut block: Block16 = [0; 16];
|
||||
for i in 0..=255 {
|
||||
for j in 0..16 {
|
||||
block[j] = (i + j) as u8;
|
||||
}
|
||||
let expected = block;
|
||||
sub_bytes(&mut block);
|
||||
inv_sub_bytes(&mut block);
|
||||
assert_eq!(block, expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shift_rows() {
|
||||
let mut block = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
let expected = [0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11];
|
||||
shift_rows(&mut block);
|
||||
assert_eq!(block, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shift_rows_inv() {
|
||||
// Test that inv_shift_rows is the inverse of shift_rows for a bunch of block values.
|
||||
let mut block: Block16 = [0; 16];
|
||||
for i in 0..=255 {
|
||||
for j in 0..16 {
|
||||
block[j] = (i + j) as u8;
|
||||
}
|
||||
let expected = block;
|
||||
shift_rows(&mut block);
|
||||
inv_shift_rows(&mut block);
|
||||
assert_eq!(block, expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mix_columns_inv() {
|
||||
// Test that inv_mix_columns is the inverse of mix_columns for a bunch of block values.
|
||||
let mut block: Block16 = [0; 16];
|
||||
for i in 0..=255 {
|
||||
for j in 0..16 {
|
||||
block[j] = (i + j) as u8;
|
||||
}
|
||||
let expected = block;
|
||||
mix_columns(&mut block);
|
||||
inv_mix_columns(&mut block);
|
||||
assert_eq!(block, expected);
|
||||
}
|
||||
}
|
||||
|
||||
/** Comparison with AES-NI instructions for CPUs that support them **/
|
||||
#[cfg(all(target_arch = "x86_64", target_feature = "aes"))]
|
||||
mod aesni {
|
||||
use super::super::*;
|
||||
|
||||
fn aes_enc_ni(block: &mut Block16, rkey: &Block16) {
|
||||
use core::arch::x86_64::{__m128i, _mm_aesenc_si128};
|
||||
|
||||
unsafe {
|
||||
let block_mm: __m128i = core::mem::transmute(*block);
|
||||
let rkey_mm: __m128i = core::mem::transmute(*rkey);
|
||||
let encrypted_mm: __m128i = _mm_aesenc_si128(block_mm, rkey_mm);
|
||||
*block = core::mem::transmute(encrypted_mm)
|
||||
}
|
||||
}
|
||||
|
||||
fn aes_enc_last_ni(block: &mut Block16, rkey: &Block16) {
|
||||
use core::arch::x86_64::{__m128i, _mm_aesenclast_si128};
|
||||
|
||||
unsafe {
|
||||
let block_mm: __m128i = core::mem::transmute(*block);
|
||||
let rkey_mm: __m128i = core::mem::transmute(*rkey);
|
||||
let encrypted_mm: __m128i = _mm_aesenclast_si128(block_mm, rkey_mm);
|
||||
*block = core::mem::transmute(encrypted_mm)
|
||||
}
|
||||
}
|
||||
|
||||
fn aes_dec_ni(block: &mut Block16, rkey: &Block16) {
|
||||
use core::arch::x86_64::{__m128i, _mm_aesdec_si128};
|
||||
|
||||
unsafe {
|
||||
let block_mm: __m128i = core::mem::transmute(*block);
|
||||
let rkey_mm: __m128i = core::mem::transmute(*rkey);
|
||||
let decrypted_mm: __m128i = _mm_aesdec_si128(block_mm, rkey_mm);
|
||||
*block = core::mem::transmute(decrypted_mm)
|
||||
}
|
||||
}
|
||||
|
||||
fn aes_dec_last_ni(block: &mut Block16, rkey: &Block16) {
|
||||
use core::arch::x86_64::{__m128i, _mm_aesdeclast_si128};
|
||||
|
||||
unsafe {
|
||||
let block_mm: __m128i = core::mem::transmute(*block);
|
||||
let rkey_mm: __m128i = core::mem::transmute(*rkey);
|
||||
let decrypted_mm: __m128i = _mm_aesdeclast_si128(block_mm, rkey_mm);
|
||||
*block = core::mem::transmute(decrypted_mm)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aes_enc_ni() {
|
||||
let mut block = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
let mut block_ni = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
let rkey = [
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
];
|
||||
aes_enc(&mut block, &rkey);
|
||||
aes_enc_ni(&mut block_ni, &rkey);
|
||||
assert_eq!(block, block_ni);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aes_enc_last_ni() {
|
||||
let mut block = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
let mut block_ni = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
let rkey = [
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
];
|
||||
aes_enc_last(&mut block, &rkey);
|
||||
aes_enc_last_ni(&mut block_ni, &rkey);
|
||||
assert_eq!(block, block_ni);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aes_dec_ni() {
|
||||
let mut block = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
let mut block_ni = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
let rkey = [
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
];
|
||||
aes_dec(&mut block, &rkey);
|
||||
aes_dec_ni(&mut block_ni, &rkey);
|
||||
assert_eq!(block, block_ni);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aes_dec_last_ni() {
|
||||
let mut block = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
let mut block_ni = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
let rkey = [
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
];
|
||||
aes_dec_last(&mut block, &rkey);
|
||||
aes_dec_last_ni(&mut block_ni, &rkey);
|
||||
assert_eq!(block, block_ni);
|
||||
}
|
||||
}
|
||||
}
|
||||
258
libraries/crypto/src/cbc.rs
Normal file
258
libraries/crypto/src/cbc.rs
Normal file
@@ -0,0 +1,258 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::util::{xor_block_16, Block16};
|
||||
use super::{Decrypt16BytesBlock, Encrypt16BytesBlock};
|
||||
|
||||
pub fn cbc_encrypt<K>(key: &K, mut iv: Block16, blocks: &mut [Block16])
|
||||
where
|
||||
K: Encrypt16BytesBlock,
|
||||
{
|
||||
for block in blocks {
|
||||
xor_block_16(block, &iv);
|
||||
key.encrypt_block(block);
|
||||
iv = *block;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cbc_decrypt<K>(key: &K, mut iv: Block16, blocks: &mut [Block16])
|
||||
where
|
||||
K: Decrypt16BytesBlock,
|
||||
{
|
||||
for block in blocks {
|
||||
let tmp = *block;
|
||||
key.decrypt_block(block);
|
||||
xor_block_16(block, &iv);
|
||||
iv = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::aes256;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_cbc_encrypt_decrypt() {
|
||||
// Test that cbc_decrypt is the inverse of cbc_encrypt for a bunch of block values.
|
||||
let enc_key = aes256::EncryptionKey::new(&[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
||||
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x1c, 0x1d, 0x1e, 0x1f,
|
||||
]);
|
||||
let dec_key = aes256::DecryptionKey::new(&enc_key);
|
||||
|
||||
for len in 0..16 {
|
||||
let mut blocks: Vec<Block16> = vec![Default::default(); len];
|
||||
for i in 0..len {
|
||||
for j in 0..16 {
|
||||
blocks[i][j] = ((len + i) * 16 + j) as u8;
|
||||
}
|
||||
}
|
||||
let iv = [
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f,
|
||||
];
|
||||
let expected = blocks.clone();
|
||||
|
||||
cbc_encrypt(&enc_key, iv, &mut blocks);
|
||||
cbc_decrypt(&dec_key, iv, &mut blocks);
|
||||
assert_eq!(blocks, expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbc_encrypt_1block_zero_iv() {
|
||||
let key = aes256::EncryptionKey::new(&[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
||||
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x1c, 0x1d, 0x1e, 0x1f,
|
||||
]);
|
||||
|
||||
let mut blocks = [[
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f,
|
||||
]];
|
||||
let iv = [0; 16];
|
||||
cbc_encrypt(&key, iv, &mut blocks);
|
||||
|
||||
let mut expected = [
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f,
|
||||
];
|
||||
key.encrypt_block(&mut expected);
|
||||
|
||||
assert_eq!(blocks, [expected]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbc_decrypt_1block_zero_iv() {
|
||||
let key = aes256::DecryptionKey::new(&aes256::EncryptionKey::new(&[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
||||
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x1c, 0x1d, 0x1e, 0x1f,
|
||||
]));
|
||||
|
||||
let mut blocks = [[
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f,
|
||||
]];
|
||||
let iv = [0; 16];
|
||||
cbc_decrypt(&key, iv, &mut blocks);
|
||||
|
||||
let mut expected = [
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f,
|
||||
];
|
||||
key.decrypt_block(&mut expected);
|
||||
|
||||
assert_eq!(blocks, [expected]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbc_encrypt_1block() {
|
||||
let key = aes256::EncryptionKey::new(&[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
||||
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x1c, 0x1d, 0x1e, 0x1f,
|
||||
]);
|
||||
|
||||
let mut blocks = [[
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f,
|
||||
]];
|
||||
let iv = [
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
|
||||
0x3e, 0x3f,
|
||||
];
|
||||
cbc_encrypt(&key, iv, &mut blocks);
|
||||
|
||||
let mut expected = [
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f,
|
||||
];
|
||||
xor_block_16(&mut expected, &iv);
|
||||
key.encrypt_block(&mut expected);
|
||||
|
||||
assert_eq!(blocks, [expected]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbc_decrypt_1block() {
|
||||
let key = aes256::DecryptionKey::new(&aes256::EncryptionKey::new(&[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
||||
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x1c, 0x1d, 0x1e, 0x1f,
|
||||
]));
|
||||
|
||||
let mut blocks = [[
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f,
|
||||
]];
|
||||
let iv = [
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
|
||||
0x3e, 0x3f,
|
||||
];
|
||||
cbc_decrypt(&key, iv, &mut blocks);
|
||||
|
||||
let mut expected = [
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f,
|
||||
];
|
||||
key.decrypt_block(&mut expected);
|
||||
xor_block_16(&mut expected, &iv);
|
||||
|
||||
assert_eq!(blocks, [expected]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbc_encrypt_2blocks() {
|
||||
let key = aes256::EncryptionKey::new(&[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
||||
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x1c, 0x1d, 0x1e, 0x1f,
|
||||
]);
|
||||
|
||||
let mut blocks = [
|
||||
[
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f,
|
||||
],
|
||||
[
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
|
||||
0x4e, 0x4f,
|
||||
],
|
||||
];
|
||||
let iv = [
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
|
||||
0x3e, 0x3f,
|
||||
];
|
||||
cbc_encrypt(&key, iv, &mut blocks);
|
||||
|
||||
let mut expected0 = [
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f,
|
||||
];
|
||||
let mut expected1 = [
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
|
||||
0x4e, 0x4f,
|
||||
];
|
||||
xor_block_16(&mut expected0, &iv);
|
||||
key.encrypt_block(&mut expected0);
|
||||
xor_block_16(&mut expected1, &expected0);
|
||||
key.encrypt_block(&mut expected1);
|
||||
|
||||
assert_eq!(blocks, [expected0, expected1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbc_decrypt_2blocks() {
|
||||
let key = aes256::DecryptionKey::new(&aes256::EncryptionKey::new(&[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
||||
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x1c, 0x1d, 0x1e, 0x1f,
|
||||
]));
|
||||
|
||||
let mut blocks = [
|
||||
[
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f,
|
||||
],
|
||||
[
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
|
||||
0x4e, 0x4f,
|
||||
],
|
||||
];
|
||||
let iv = [
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
|
||||
0x3e, 0x3f,
|
||||
];
|
||||
cbc_decrypt(&key, iv, &mut blocks);
|
||||
|
||||
let mut expected0 = [
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f,
|
||||
];
|
||||
let mut expected1 = [
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
|
||||
0x4e, 0x4f,
|
||||
];
|
||||
key.decrypt_block(&mut expected1);
|
||||
xor_block_16(&mut expected1, &expected0);
|
||||
key.decrypt_block(&mut expected0);
|
||||
xor_block_16(&mut expected0, &iv);
|
||||
|
||||
assert_eq!(blocks, [expected0, expected1]);
|
||||
}
|
||||
}
|
||||
346
libraries/crypto/src/ec/exponent256.rs
Normal file
346
libraries/crypto/src/ec/exponent256.rs
Normal file
@@ -0,0 +1,346 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::super::rng256::Rng256;
|
||||
use super::int256::{Digit, Int256};
|
||||
use core::ops::Mul;
|
||||
use subtle::{self, Choice, ConditionallySelectable, CtOption};
|
||||
|
||||
// An exponent on the elliptic curve, that is an element modulo the curve order N.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
// TODO: remove this Default once https://github.com/dalek-cryptography/subtle/issues/63 is
|
||||
// resolved.
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "derive_debug", derive(Debug))]
|
||||
pub struct ExponentP256 {
|
||||
int: Int256,
|
||||
}
|
||||
|
||||
impl ConditionallySelectable for ExponentP256 {
|
||||
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
||||
Self {
|
||||
int: Int256::conditional_select(&a.int, &b.int, choice),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExponentP256 {
|
||||
/** Constructors **/
|
||||
pub fn from_int_checked(int: Int256) -> CtOption<ExponentP256> {
|
||||
CtOption::new(ExponentP256 { int }, int.ct_lt(&Int256::N))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
// Normally the ExponentP256 type guarantees that its values stay in [0, N[ because N is the
|
||||
// curve order and therefore exponents >= N are equivalent to their reduction modulo N.
|
||||
// This unsafe function is only used in tests to check that N is indeed the curve order.
|
||||
pub unsafe fn from_int_unchecked(int: Int256) -> ExponentP256 {
|
||||
ExponentP256 { int }
|
||||
}
|
||||
|
||||
pub fn modn(int: Int256) -> ExponentP256 {
|
||||
ExponentP256 {
|
||||
int: int.modd(&Int256::N),
|
||||
}
|
||||
}
|
||||
|
||||
/** Helpful getters **/
|
||||
pub fn bit(&self, i: usize) -> Digit {
|
||||
self.int.bit(i)
|
||||
}
|
||||
|
||||
pub fn to_int(self) -> Int256 {
|
||||
self.int
|
||||
}
|
||||
|
||||
pub fn is_zero(&self) -> subtle::Choice {
|
||||
self.int.is_zero()
|
||||
}
|
||||
|
||||
pub fn non_zero(self) -> CtOption<NonZeroExponentP256> {
|
||||
CtOption::new(NonZeroExponentP256 { e: self }, !self.is_zero())
|
||||
}
|
||||
|
||||
/** Arithmetic **/
|
||||
pub fn mul_top(&self, other: &Int256, other_top: Digit) -> ExponentP256 {
|
||||
ExponentP256 {
|
||||
int: Int256::modmul_top(&self.int, other, other_top, &Int256::N),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Arithmetic operators **/
|
||||
impl Mul for &ExponentP256 {
|
||||
type Output = ExponentP256;
|
||||
|
||||
fn mul(self, other: &ExponentP256) -> ExponentP256 {
|
||||
ExponentP256 {
|
||||
int: Int256::modmul(&self.int, &other.int, &Int256::N),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A non-zero exponent on the elliptic curve.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
// TODO: remove this Default once https://github.com/dalek-cryptography/subtle/issues/63 is
|
||||
// resolved.
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "derive_debug", derive(Debug))]
|
||||
pub struct NonZeroExponentP256 {
|
||||
e: ExponentP256,
|
||||
}
|
||||
|
||||
impl ConditionallySelectable for NonZeroExponentP256 {
|
||||
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
||||
Self {
|
||||
e: ExponentP256::conditional_select(&a.e, &b.e, choice),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NonZeroExponentP256 {
|
||||
/** RNG **/
|
||||
// Generates a uniformly distributed element 0 < k < N
|
||||
pub fn gen_uniform<R>(r: &mut R) -> NonZeroExponentP256
|
||||
where
|
||||
R: Rng256,
|
||||
{
|
||||
loop {
|
||||
let x = Int256::gen_uniform_256(r);
|
||||
if bool::from(Int256::N_MIN_2.ct_lt(&x)) {
|
||||
continue;
|
||||
}
|
||||
// At this point, x <= n - 2.
|
||||
// We add 1 so that 0 < result < n.
|
||||
return NonZeroExponentP256 {
|
||||
e: ExponentP256 { int: (&x + 1).0 },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/** Constructors **/
|
||||
pub fn from_int_checked(int: Int256) -> CtOption<NonZeroExponentP256> {
|
||||
ExponentP256::from_int_checked(int)
|
||||
.and_then(|e| CtOption::new(NonZeroExponentP256 { e }, !e.is_zero()))
|
||||
}
|
||||
|
||||
/** Helpful getters **/
|
||||
pub fn to_int(self) -> Int256 {
|
||||
self.e.to_int()
|
||||
}
|
||||
|
||||
pub fn as_exponent(&self) -> &ExponentP256 {
|
||||
&self.e
|
||||
}
|
||||
|
||||
/** Arithmetic **/
|
||||
// Compute the inverse modulo N. This uses Fermat's little theorem for constant-timeness.
|
||||
pub fn inv(&self) -> NonZeroExponentP256 {
|
||||
NonZeroExponentP256 {
|
||||
e: ExponentP256 {
|
||||
int: self.e.int.modpow(&Int256::N_MIN_2, &Int256::N),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn inv_vartime(&self) -> NonZeroExponentP256 {
|
||||
NonZeroExponentP256 {
|
||||
e: ExponentP256 {
|
||||
int: self.e.int.modinv_vartime(&Int256::N),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Arithmetic operators **/
|
||||
impl Mul for &NonZeroExponentP256 {
|
||||
type Output = NonZeroExponentP256;
|
||||
|
||||
// The product of two non-zero elements is also non-zero, because the curve order N is prime.
|
||||
fn mul(self, other: &NonZeroExponentP256) -> NonZeroExponentP256 {
|
||||
NonZeroExponentP256 {
|
||||
e: &self.e * &other.e,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod test {
|
||||
use super::super::montgomery::Montgomery;
|
||||
use super::*;
|
||||
use crate::util::ToOption;
|
||||
|
||||
const ZERO: ExponentP256 = ExponentP256 { int: Int256::ZERO };
|
||||
const ONE: NonZeroExponentP256 = NonZeroExponentP256 {
|
||||
e: ExponentP256 { int: Int256::ONE },
|
||||
};
|
||||
const N_MIN_1_INT: Int256 = Int256::new([
|
||||
0xfc632550, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, 0xffffffff, 0xffffffff, 0x00000000,
|
||||
0xffffffff,
|
||||
]);
|
||||
const N_MIN_1: NonZeroExponentP256 = NonZeroExponentP256 {
|
||||
e: ExponentP256 { int: N_MIN_1_INT },
|
||||
};
|
||||
|
||||
fn get_nonzero_test_values() -> Vec<NonZeroExponentP256> {
|
||||
let mut values: Vec<NonZeroExponentP256> = Montgomery::PRECOMPUTED
|
||||
.iter()
|
||||
.flatten()
|
||||
.flatten()
|
||||
.map(|x| {
|
||||
ExponentP256::modn(x.montgomery_to_field().to_int())
|
||||
.non_zero()
|
||||
.unwrap()
|
||||
})
|
||||
.collect();
|
||||
values.extend(
|
||||
super::super::int256::test::get_nonzero_test_values()
|
||||
.iter()
|
||||
.filter_map(|&x| {
|
||||
let y = ExponentP256::modn(x).non_zero();
|
||||
if bool::from(y.is_some()) {
|
||||
Some(y.unwrap())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
);
|
||||
values.push(ONE);
|
||||
values
|
||||
}
|
||||
|
||||
pub fn get_test_values() -> Vec<ExponentP256> {
|
||||
let mut values: Vec<ExponentP256> = get_nonzero_test_values()
|
||||
.iter()
|
||||
.map(|x| *x.as_exponent())
|
||||
.collect();
|
||||
values.push(ZERO);
|
||||
values
|
||||
}
|
||||
|
||||
/** Constructors **/
|
||||
#[test]
|
||||
fn test_from_int_checked() {
|
||||
assert_eq!(
|
||||
ExponentP256::from_int_checked(Int256::ZERO).to_option(),
|
||||
Some(ExponentP256 { int: Int256::ZERO })
|
||||
);
|
||||
assert_eq!(
|
||||
ExponentP256::from_int_checked(Int256::ONE).to_option(),
|
||||
Some(ExponentP256 { int: Int256::ONE })
|
||||
);
|
||||
assert_eq!(
|
||||
ExponentP256::from_int_checked(N_MIN_1_INT).to_option(),
|
||||
Some(ExponentP256 { int: N_MIN_1_INT })
|
||||
);
|
||||
assert_eq!(ExponentP256::from_int_checked(Int256::N).to_option(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_modn() {
|
||||
assert_eq!(
|
||||
ExponentP256::modn(Int256::ZERO),
|
||||
ExponentP256 { int: Int256::ZERO }
|
||||
);
|
||||
assert_eq!(
|
||||
ExponentP256::modn(Int256::ONE),
|
||||
ExponentP256 { int: Int256::ONE }
|
||||
);
|
||||
assert_eq!(
|
||||
ExponentP256::modn(N_MIN_1_INT),
|
||||
ExponentP256 { int: N_MIN_1_INT }
|
||||
);
|
||||
assert_eq!(
|
||||
ExponentP256::modn(Int256::N),
|
||||
ExponentP256 { int: Int256::ZERO }
|
||||
);
|
||||
}
|
||||
|
||||
/** Arithmetic operations: inverse **/
|
||||
#[test]
|
||||
fn test_inv_is_inv_vartime() {
|
||||
for x in &get_nonzero_test_values() {
|
||||
assert_eq!(x.inv(), x.inv_vartime());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_self_times_inv_is_one() {
|
||||
for x in &get_nonzero_test_values() {
|
||||
assert_eq!(x * &x.inv(), ONE);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inv_inv() {
|
||||
for x in get_nonzero_test_values() {
|
||||
assert_eq!(x.inv().inv(), x);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_well_known_inverses() {
|
||||
assert_eq!(ONE.inv(), ONE);
|
||||
assert_eq!(N_MIN_1.inv(), N_MIN_1);
|
||||
}
|
||||
|
||||
/** RNG **/
|
||||
// Mock rng that samples through a list of values, then panics.
|
||||
struct StressTestingRng {
|
||||
values: Vec<Int256>,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl StressTestingRng {
|
||||
pub fn new(values: Vec<Int256>) -> StressTestingRng {
|
||||
StressTestingRng { values, index: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng256 for StressTestingRng {
|
||||
// This function is unused, as we redefine gen_uniform_u32x8.
|
||||
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn gen_uniform_u32x8(&mut self) -> [u32; 8] {
|
||||
let result = self.values[self.index].digits();
|
||||
self.index += 1;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uniform_non_zero_is_below_n() {
|
||||
let mut rng = StressTestingRng::new(vec![
|
||||
Int256::new([
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff,
|
||||
]),
|
||||
Int256::N,
|
||||
N_MIN_1.to_int(),
|
||||
Int256::N_MIN_2,
|
||||
]);
|
||||
|
||||
assert_eq!(NonZeroExponentP256::gen_uniform(&mut rng), N_MIN_1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uniform_n_is_above_zero() {
|
||||
let mut rng = StressTestingRng::new(vec![Int256::ZERO]);
|
||||
|
||||
assert_eq!(NonZeroExponentP256::gen_uniform(&mut rng), ONE);
|
||||
}
|
||||
}
|
||||
260
libraries/crypto/src/ec/gfp256.rs
Normal file
260
libraries/crypto/src/ec/gfp256.rs
Normal file
@@ -0,0 +1,260 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::int256::{Digit, Int256};
|
||||
use core::ops::Mul;
|
||||
use subtle::Choice;
|
||||
|
||||
// A field element on the elliptic curve, that is an element modulo the prime P.
|
||||
// This is the format used to serialize coordinates of points on the curve.
|
||||
// This implements enough methods to validate points and to convert them to/from the Montgomery
|
||||
// form, which is more convenient to operate on.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct GFP256 {
|
||||
int: Int256,
|
||||
}
|
||||
|
||||
impl GFP256 {
|
||||
pub const ZERO: GFP256 = GFP256 { int: Int256::ZERO };
|
||||
pub const ONE: GFP256 = GFP256 { int: Int256::ONE };
|
||||
pub const B: GFP256 = GFP256 { int: Int256::B };
|
||||
pub const R: GFP256 = GFP256 { int: Int256::R };
|
||||
pub const R_INV: GFP256 = GFP256 { int: Int256::R_INV };
|
||||
|
||||
/** Constructors **/
|
||||
pub fn from_int_checked(int: Int256) -> Option<GFP256> {
|
||||
if bool::from(int.ct_lt(&Int256::P)) {
|
||||
Some(GFP256 { int })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/** Helpful getters **/
|
||||
pub fn to_int(self) -> Int256 {
|
||||
self.int
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> Choice {
|
||||
self.int.is_zero()
|
||||
}
|
||||
|
||||
/** Arithmetic **/
|
||||
pub fn mul_top(&self, other: &Int256, other_top: Digit) -> GFP256 {
|
||||
GFP256 {
|
||||
int: Int256::modmul_top(&self.int, other, other_top, &Int256::P),
|
||||
}
|
||||
}
|
||||
|
||||
/** Point validation **/
|
||||
// Verify that all of the following are true:
|
||||
// * y^2 == x^3 - 3x + b mod p
|
||||
// * 0 < x < p
|
||||
// * 0 < y < p
|
||||
//
|
||||
// Not constant time.
|
||||
pub fn is_valid_point_vartime(x: &GFP256, y: &GFP256) -> bool {
|
||||
if bool::from(x.is_zero()) || bool::from(y.is_zero()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// y^2
|
||||
let y2 = y * y;
|
||||
|
||||
// x^3
|
||||
let x2 = x * x;
|
||||
let x3 = &x2 * x;
|
||||
|
||||
// x^3 - 3x + b
|
||||
let mut xx = x3;
|
||||
xx = xx.sub_vartime(x);
|
||||
xx = xx.sub_vartime(x);
|
||||
xx = xx.sub_vartime(x);
|
||||
xx = xx.add_vartime(&GFP256::B);
|
||||
|
||||
xx == y2
|
||||
}
|
||||
|
||||
/** Arithmetic operators **/
|
||||
fn add_vartime(self, other: &GFP256) -> GFP256 {
|
||||
GFP256 {
|
||||
int: Int256::modadd_vartime(&self.int, &other.int, &Int256::P),
|
||||
}
|
||||
}
|
||||
|
||||
fn sub_vartime(self, other: &GFP256) -> GFP256 {
|
||||
GFP256 {
|
||||
int: Int256::modsub_vartime(&self.int, &other.int, &Int256::P),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Arithmetic operators **/
|
||||
impl Mul for &GFP256 {
|
||||
type Output = GFP256;
|
||||
|
||||
fn mul(self, other: &GFP256) -> GFP256 {
|
||||
GFP256 {
|
||||
int: Int256::modmul(&self.int, &other.int, &Int256::P),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "derive_debug")]
|
||||
impl core::fmt::Debug for GFP256 {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
write!(f, "GFP256::{:?}", self.int)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::montgomery::Montgomery;
|
||||
use super::*;
|
||||
use core::ops::{Add, Sub};
|
||||
|
||||
const P_MIN_1_INT: Int256 = Int256::new([
|
||||
0xfffffffe, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000001,
|
||||
0xffffffff,
|
||||
]);
|
||||
|
||||
fn get_test_values() -> Vec<GFP256> {
|
||||
let mut values: Vec<GFP256> = Montgomery::PRECOMPUTED
|
||||
.iter()
|
||||
.flatten()
|
||||
.flatten()
|
||||
.map(|x| x.montgomery_to_field())
|
||||
.collect();
|
||||
values.extend(
|
||||
super::super::int256::test::get_1bit_one_test_values()
|
||||
.iter()
|
||||
.filter_map(|&x| GFP256::from_int_checked(x)),
|
||||
);
|
||||
values.extend(
|
||||
super::super::int256::test::get_1bit_zero_test_values()
|
||||
.iter()
|
||||
.filter_map(|&x| GFP256::from_int_checked(x)),
|
||||
);
|
||||
values.push(GFP256::ZERO);
|
||||
values.push(GFP256::ONE);
|
||||
values.push(GFP256::B);
|
||||
values
|
||||
}
|
||||
|
||||
/** Arithmetic operators, only for tests as these are not constant time **/
|
||||
impl Add for &GFP256 {
|
||||
type Output = GFP256;
|
||||
|
||||
fn add(self, other: &GFP256) -> GFP256 {
|
||||
self.add_vartime(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for &GFP256 {
|
||||
type Output = GFP256;
|
||||
|
||||
fn sub(self, other: &GFP256) -> GFP256 {
|
||||
self.sub_vartime(other)
|
||||
}
|
||||
}
|
||||
|
||||
/** Constructors **/
|
||||
#[test]
|
||||
fn test_from_int_checked() {
|
||||
assert_eq!(
|
||||
GFP256::from_int_checked(Int256::ZERO),
|
||||
Some(GFP256 { int: Int256::ZERO })
|
||||
);
|
||||
assert_eq!(
|
||||
GFP256::from_int_checked(Int256::ONE),
|
||||
Some(GFP256 { int: Int256::ONE })
|
||||
);
|
||||
assert_eq!(
|
||||
GFP256::from_int_checked(P_MIN_1_INT),
|
||||
Some(GFP256 { int: P_MIN_1_INT })
|
||||
);
|
||||
assert_eq!(GFP256::from_int_checked(Int256::P), None);
|
||||
}
|
||||
|
||||
/** Point validation **/
|
||||
// See point.rs
|
||||
|
||||
/** Arithmetic operators **/
|
||||
// Due to the 3 nested loops, this test is super slow with debug assertions enabled.
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[test]
|
||||
fn test_add_is_associative() {
|
||||
for x in &get_test_values() {
|
||||
for y in &get_test_values() {
|
||||
for z in &get_test_values() {
|
||||
assert_eq!(&(x + y) + z, x + &(y + z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_is_commutative() {
|
||||
for x in &get_test_values() {
|
||||
for y in &get_test_values() {
|
||||
assert_eq!(x + y, y + x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_sub() {
|
||||
for x in &get_test_values() {
|
||||
for y in &get_test_values() {
|
||||
assert_eq!(&(x - y) + y, *x);
|
||||
assert_eq!(&(x + y) - y, *x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Due to the 3 nested loops, this test is super slow with debug assertions enabled.
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[test]
|
||||
fn test_mul_is_associative() {
|
||||
for x in &get_test_values() {
|
||||
for y in &get_test_values() {
|
||||
for z in &get_test_values() {
|
||||
assert_eq!(&(x * y) * z, x * &(y * z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mul_is_commutative() {
|
||||
for x in &get_test_values() {
|
||||
for y in &get_test_values() {
|
||||
assert_eq!(x * y, y * x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Due to the 3 nested loops, this test is super slow with debug assertions enabled.
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[test]
|
||||
fn test_mul_is_distributive() {
|
||||
for x in &get_test_values() {
|
||||
for y in &get_test_values() {
|
||||
for z in &get_test_values() {
|
||||
assert_eq!(&(x + y) * z, &(x * z) + &(y * z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1181
libraries/crypto/src/ec/int256.rs
Normal file
1181
libraries/crypto/src/ec/int256.rs
Normal file
File diff suppressed because it is too large
Load Diff
20
libraries/crypto/src/ec/mod.rs
Normal file
20
libraries/crypto/src/ec/mod.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
pub mod exponent256;
|
||||
mod gfp256;
|
||||
pub mod int256;
|
||||
mod montgomery;
|
||||
pub mod point;
|
||||
mod precomputed;
|
||||
1109
libraries/crypto/src/ec/montgomery.rs
Normal file
1109
libraries/crypto/src/ec/montgomery.rs
Normal file
File diff suppressed because it is too large
Load Diff
1034
libraries/crypto/src/ec/point.rs
Normal file
1034
libraries/crypto/src/ec/point.rs
Normal file
File diff suppressed because it is too large
Load Diff
324
libraries/crypto/src/ec/precomputed.rs
Normal file
324
libraries/crypto/src/ec/precomputed.rs
Normal file
@@ -0,0 +1,324 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::montgomery::{Montgomery, NLIMBS};
|
||||
|
||||
pub const PRECOMPUTED: [[[Montgomery; 2]; 15]; 2] = [
|
||||
[
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[0]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[1]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[2]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[3]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[4]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[5]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[6]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[7]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[8]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[9]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[10]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[11]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[12]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[13]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[14]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[15]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[16]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[17]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[18]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[19]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[20]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[21]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[22]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[23]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[24]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[25]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[26]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[27]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[28]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[29]),
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[30]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[31]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[32]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[33]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[34]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[35]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[36]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[37]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[38]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[39]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[40]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[41]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[42]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[43]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[44]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[45]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[46]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[47]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[48]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[49]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[50]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[51]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[52]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[53]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[54]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[55]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[56]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[57]),
|
||||
],
|
||||
[
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[58]),
|
||||
Montgomery::new(PRECOMPUTED_LIMBS[59]),
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
const PRECOMPUTED_LIMBS: [[u32; NLIMBS]; 60] = [
|
||||
[0x11522878, 0x0e730d41, 0x0db60179, 0x04afe2ff, 0x12883add, 0x0caddd88, 0x119e7edc, 0x0d4a6eab, 0x03120bee],
|
||||
[0x1d2aac15, 0x0f25357c, 0x19e45cdd, 0x05c721d0, 0x1992c5a5, 0x0a237487, 0x0154ba21, 0x014b10bb, 0x00ae3fe3],
|
||||
[0x0d41a576, 0x0922fc51, 0x0234994f, 0x060b60d3, 0x164586ae, 0x0ce95f18, 0x1fe49073, 0x03fa36cc, 0x05ebcd2c],
|
||||
[0x0b402f2f, 0x015c70bf, 0x1561925c, 0x05a26704, 0x0da91e90, 0x0cdc1c7f, 0x1ea12446, 0x0e1ade1e, 0x0ec91f22],
|
||||
[0x026f7778, 0x0566847e, 0x0a0bec9e, 0x0234f453, 0x1a31f21a, 0x0d85e75c, 0x056c7109, 0x0a267a00, 0x0b57c050],
|
||||
[0x0098fb57, 0x0aa837cc, 0x060c0792, 0x0cfa5e19, 0x061bab9e, 0x0589e39b, 0x00a324c5, 0x07d6dee7, 0x02976e4b],
|
||||
[0x1fc4124a, 0x0a8c244b, 0x1ce86762, 0x0cd61c7e, 0x1831c8e0, 0x075774e1, 0x1d96a5a9, 0x0843a649, 0x0c3ab0fa],
|
||||
[0x06e2e7d5, 0x07673a2a, 0x178b65e8, 0x04003e9b, 0x1a1f11c2, 0x007816ea, 0x0f643e11, 0x058c43df, 0x0f423fc2],
|
||||
[0x19633ffa, 0x0891f2b2, 0x123c231c, 0x046add8c, 0x054700dd, 0x059e2b17, 0x172db40f, 0x083e277d, 0x0b0dd609],
|
||||
[0x0fd1da12, 0x035c6e52, 0x19ede20c, 0x0d19e0c0, 0x097d0f40, 0x0b015b19, 0x0449e3f5, 0x00e10c9e, 0x033ab581],
|
||||
[0x056a67ab, 0x0577734d, 0x1dddc062, 0x0c57b10d, 0x0149b39d, 0x026a9e7b, 0x0c35df9f, 0x048764cd, 0x076dbcca],
|
||||
[0x0ca4b366, 0x0e9303ab, 0x1a7480e7, 0x057e9e81, 0x1e13eb50, 0x0f466cf3, 0x06f16b20, 0x04ba3173, 0x0c168c33],
|
||||
[0x15cb5439, 0x06a38e11, 0x073658bd, 0x0b29564f, 0x03f6dc5b, 0x0053b97e, 0x1322c4c0, 0x065dd7ff, 0x03a1e4f6],
|
||||
[0x14e614aa, 0x09246317, 0x1bc83aca, 0x0ad97eed, 0x0d38ce4a, 0x0f82b006, 0x0341f077, 0x0a6add89, 0x04894acd],
|
||||
[0x09f162d5, 0x0f8410ef, 0x1b266a56, 0x00d7f223, 0x03e0cb92, 0x0e39b672, 0x06a2901a, 0x069a8556, 0x0007e7c0],
|
||||
[0x09b7d8d3, 0x00309a80, 0x1ad05f7f, 0x0c2fb5dd, 0x0cbfd41d, 0x09ceb638, 0x1051825c, 0x0da0cf5b, 0x0812e881],
|
||||
[0x06f35669, 0x06a56f2c, 0x1df8d184, 0x00345820, 0x1477d477, 0x01645db1, 0x0be80c51, 0x0c22be3e, 0x0e35e65a],
|
||||
[0x1aeb7aa0, 0x0c375315, 0x0f67bc99, 0x07fdd7b9, 0x191fc1be, 0x0061235d, 0x02c184e9, 0x01c5a839, 0x047a1e26],
|
||||
[0x0b7cb456, 0x093e225d, 0x14f3c6ed, 0x0ccc1ac9, 0x17fe37f3, 0x04988989, 0x1a90c502, 0x02f32042, 0x0a17769b],
|
||||
[0x0afd8c7c, 0x08191c6e, 0x1dcdb237, 0x016200c0, 0x107b32a1, 0x066c08db, 0x10d06a02, 0x0003fc93, 0x05620023],
|
||||
[0x16722b27, 0x068b5c59, 0x0270fcfc, 0x0fad0ecc, 0x0e5de1c2, 0x0eab466b, 0x02fc513c, 0x0407f75c, 0x0baab133],
|
||||
[0x09705fe9, 0x0b88b8e7, 0x0734c993, 0x01e1ff8f, 0x19156970, 0x0abd0f00, 0x10469ea7, 0x03293ac0, 0x0cdc98aa],
|
||||
[0x01d843fd, 0x0e14bfe8, 0x15be825f, 0x008b5212, 0x0eb3fb67, 0x081cbd29, 0x0bc62f16, 0x02b6fcc7, 0x0f5a4e29],
|
||||
[0x13560b66, 0x0c0b6ac2, 0x051ae690, 0x0d41e271, 0x0f3e9bd4, 0x01d70aab, 0x01029f72, 0x073e1c35, 0x0ee70fbc],
|
||||
[0x0ad81baf, 0x09ecc49a, 0x086c741e, 0x0fe6be30, 0x176752e7, 0x0023d416, 0x1f83de85, 0x027de188, 0x066f70b8],
|
||||
[0x181cd51f, 0x096b6e4c, 0x188f2335, 0x0a5df759, 0x17a77eb6, 0x0feb0e73, 0x154ae914, 0x02f3ec51, 0x03826b59],
|
||||
[0x0b91f17d, 0x01c72949, 0x1362bf0a, 0x0e23fddf, 0x0a5614b0, 0x000f7d8f, 0x00079061, 0x0823d9d2, 0x08213f39],
|
||||
[0x1128ae0b, 0x0d095d05, 0x0b85c0c2, 0x01ecb2ef, 0x024ddc84, 0x0e35e901, 0x18411a4a, 0x0f5ddc3d, 0x03786689],
|
||||
[0x052260e8, 0x05ae3564, 0x0542b10d, 0x08d93a45, 0x19952aa4, 0x0996cc41, 0x1051a729, 0x04be3499, 0x052b23aa],
|
||||
[0x109f307e, 0x06f5b6bb, 0x1f84e1e7, 0x077a0cfa, 0x10c4df3f, 0x025a02ea, 0x0b048035, 0x0e31de66, 0x0c6ecaa3],
|
||||
[0x028ea335, 0x02886024, 0x1372f020, 0x00f55d35, 0x15e4684c, 0x0f2a9e17, 0x1a4a7529, 0x0cb7beb1, 0x0b2a78a1],
|
||||
[0x1ab21f1f, 0x06361ccf, 0x06c9179d, 0x0b135627, 0x1267b974, 0x04408bad, 0x1cbff658, 0x0e3d6511, 0x00c7d76f],
|
||||
[0x01cc7a69, 0x0e7ee31b, 0x054fab4f, 0x002b914f, 0x1ad27a30, 0x0cd3579e, 0x0c50124c, 0x050daa90, 0x00b13f72],
|
||||
[0x0b06aa75, 0x070f5cc6, 0x1649e5aa, 0x084a5312, 0x0329043c, 0x041c4011, 0x13d32411, 0x0b04a838, 0x0d760d2d],
|
||||
[0x1713b532, 0x0baa0c03, 0x084022ab, 0x06bcf5c1, 0x02f45379, 0x018ae070, 0x18c9e11e, 0x020bca9a, 0x066f496b],
|
||||
[0x03eef294, 0x067500d2, 0x0d7f613c, 0x002dbbeb, 0x0b741038, 0x0e04133f, 0x1582968d, 0x0be985f7, 0x01acbc1a],
|
||||
[0x1a6a939f, 0x033e50f6, 0x0d665ed4, 0x0b4b7bd6, 0x1e5a3799, 0x06b33847, 0x17fa56ff, 0x065ef930, 0x0021dc4a],
|
||||
[0x02b37659, 0x0450fe17, 0x0b357b65, 0x0df5efac, 0x15397bef, 0x09d35a7f, 0x112ac15f, 0x0624e62e, 0x0a90ae2f],
|
||||
[0x107eecd2, 0x01f69bbe, 0x077d6bce, 0x05741394, 0x13c684fc, 0x0950c910, 0x0725522b, 0x0dc78583, 0x040eeabb],
|
||||
[0x1fde328a, 0x0bd61d96, 0x0d28c387, 0x09e77d89, 0x12550c40, 0x0759cb7d, 0x0367ef34, 0x0ae2a960, 0x091b8bdc],
|
||||
[0x093462a9, 0x00f469ef, 0x0b2e9aef, 0x0d2ca771, 0x054e1f42, 0x007aaa49, 0x06316abb, 0x02413c8e, 0x05425bf9],
|
||||
[0x1bed3e3a, 0x0f272274, 0x1f5e7326, 0x06416517, 0x0ea27072, 0x09cedea7, 0x006e7633, 0x07c91952, 0x0d806dce],
|
||||
[0x08e2a7e1, 0x0e421e1a, 0x0418c9e1, 0x01dbc890, 0x1b395c36, 0x0a1dc175, 0x1dc4ef73, 0x08956f34, 0x0e4b5cf2],
|
||||
[0x1b0d3a18, 0x03194a36, 0x06c2641f, 0x0e44124c, 0x0a2f4eaa, 0x0a8c25ba, 0x0f927ed7, 0x0627b614, 0x07371cca],
|
||||
[0x0ba16694, 0x0417bc03, 0x07c0a7e3, 0x09c35c19, 0x1168a205, 0x08b6b00d, 0x10e3edc9, 0x09c19bf2, 0x05882229],
|
||||
[0x1b2b4162, 0x0a5cef1a, 0x1543622b, 0x09bd433e, 0x0364e04d, 0x07480792, 0x05c9b5b3, 0x0e85ff25, 0x0408ef57],
|
||||
[0x1814cfa4, 0x0121b41b, 0x0d248a0f, 0x03b05222, 0x039bb16a, 0x0c75966d, 0x0a038113, 0x0a4a1769, 0x011fbc6c],
|
||||
[0x0917e50e, 0x0eec3da8, 0x169d6eac, 0x010c1699, 0x0a416153, 0x0f724912, 0x15cd60b7, 0x04acbad9, 0x05efc5fa],
|
||||
[0x0f150ed7, 0x00122b51, 0x1104b40a, 0x0cb7f442, 0x0fbb28ff, 0x06ac53ca, 0x196142cc, 0x07bf0fa9, 0x00957651],
|
||||
[0x04e0f215, 0x0ed439f8, 0x03f46bd5, 0x05ace82f, 0x110916b6, 0x006db078, 0x0ffd7d57, 0x0f2ecaac, 0x0ca86dec],
|
||||
[0x15d6b2da, 0x0965ecc9, 0x1c92b4c2, 0x001f3811, 0x1cb080f5, 0x02d8b804, 0x19d1c12d, 0x0f20bd46, 0x01951fa7],
|
||||
[0x0a3656c3, 0x0523a425, 0x0fcd0692, 0x0d44ddc8, 0x131f0f5b, 0x0af80e4a, 0x0cd9fc74, 0x099bb618, 0x02db944c],
|
||||
[0x0a673090, 0x01c210e1, 0x178c8d23, 0x01474383, 0x10b8743d, 0x0985a55b, 0x02e74779, 0x00576138, 0x09587927],
|
||||
[0x133130fa, 0x0be05516, 0x09f4d619, 0x0bb62570, 0x099ec591, 0x0d9468fe, 0x1d07782d, 0x0fc72e0b, 0x0701b298],
|
||||
[0x1863863b, 0x085954b8, 0x121a0c36, 0x09e7fedf, 0x0f64b429, 0x09b9d71e, 0x14e2f5d8, 0x0f858d3a, 0x0942eea8],
|
||||
[0x0da5b765, 0x06edafff, 0x0a9d18cc, 0x0c65e4ba, 0x1c747e86, 0x0e4ea915, 0x1981d7a1, 0x08395659, 0x052ed4e2],
|
||||
[0x087d43b7, 0x037ab11b, 0x19d292ce, 0x0f8d4692, 0x18c3053f, 0x08863e13, 0x04c146c0, 0x06bdf55a, 0x04e4457d],
|
||||
[0x16152289, 0x0ac78ec2, 0x1a59c5a2, 0x02028b97, 0x071c2d01, 0x0295851f, 0x0404747b, 0x0878558d, 0x07d29aa4],
|
||||
[0x13d8341f, 0x08daefd7, 0x139c972d, 0x06b7ea75, 0x0d4a9dde, 0x0ff163d8, 0x081d55d7, 0x0a5bef68, 0x0b7b30d8],
|
||||
[0x0be73d6f, 0x0aa88141, 0x0d976c81, 0x07e7a9cc, 0x18beb771, 0x0d773cbd, 0x13f51951, 0x09d0c177, 0x01c49a78],
|
||||
];
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::montgomery::{BOTTOM_28_BITS, BOTTOM_29_BITS};
|
||||
use super::super::point::test::{power_of_two, precomputed};
|
||||
use super::super::point::PointProjective;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_precomputed_bits() {
|
||||
for x in PRECOMPUTED_LIMBS.iter() {
|
||||
for (i, &limb) in x.iter().enumerate() {
|
||||
if i & 1 == 0 {
|
||||
assert_eq!(limb & BOTTOM_29_BITS, limb);
|
||||
} else {
|
||||
assert_eq!(limb & BOTTOM_28_BITS, limb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_precomputed_powers_of_g_are_correct() {
|
||||
let gen = PointProjective::from_affine(&precomputed(0, 0));
|
||||
let g32 = power_of_two(gen, 32);
|
||||
let g64 = power_of_two(gen, 64);
|
||||
let g96 = power_of_two(gen, 96);
|
||||
let g128 = power_of_two(gen, 128);
|
||||
let g160 = power_of_two(gen, 160);
|
||||
let g192 = power_of_two(gen, 192);
|
||||
let g224 = power_of_two(gen, 224);
|
||||
|
||||
assert_eq!(
|
||||
PointProjective::from_affine(&precomputed(0, 0b0001 - 1)),
|
||||
gen
|
||||
);
|
||||
assert_eq!(
|
||||
PointProjective::from_affine(&precomputed(0, 0b0010 - 1)),
|
||||
g64
|
||||
);
|
||||
assert_eq!(
|
||||
PointProjective::from_affine(&precomputed(0, 0b0100 - 1)),
|
||||
g128
|
||||
);
|
||||
assert_eq!(
|
||||
PointProjective::from_affine(&precomputed(0, 0b1000 - 1)),
|
||||
g192
|
||||
);
|
||||
assert_eq!(
|
||||
PointProjective::from_affine(&precomputed(1, 0b0001 - 1)),
|
||||
g32
|
||||
);
|
||||
assert_eq!(
|
||||
PointProjective::from_affine(&precomputed(1, 0b0010 - 1)),
|
||||
g96
|
||||
);
|
||||
assert_eq!(
|
||||
PointProjective::from_affine(&precomputed(1, 0b0100 - 1)),
|
||||
g160
|
||||
);
|
||||
assert_eq!(
|
||||
PointProjective::from_affine(&precomputed(1, 0b1000 - 1)),
|
||||
g224
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_precomputed_table_0_is_correct() {
|
||||
let gen = PointProjective::from_affine(&precomputed(0, 0));
|
||||
let g64 = power_of_two(gen, 64);
|
||||
let g128 = power_of_two(gen, 128);
|
||||
let g192 = power_of_two(gen, 192);
|
||||
|
||||
for i in 1..16 {
|
||||
let mut x = PointProjective::INFINITY;
|
||||
if i & 1 != 0 {
|
||||
x = &x + &gen;
|
||||
}
|
||||
if i & 2 != 0 {
|
||||
x = &x + &g64;
|
||||
}
|
||||
if i & 4 != 0 {
|
||||
x = &x + &g128;
|
||||
}
|
||||
if i & 8 != 0 {
|
||||
x = &x + &g192;
|
||||
}
|
||||
assert_eq!(PointProjective::from_affine(&precomputed(0, i - 1)), x);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_precomputed_table_1_is_correct() {
|
||||
let gen = PointProjective::from_affine(&precomputed(0, 0));
|
||||
let g32 = power_of_two(gen, 32);
|
||||
let g96 = power_of_two(gen, 96);
|
||||
let g160 = power_of_two(gen, 160);
|
||||
let g224 = power_of_two(gen, 224);
|
||||
|
||||
for i in 1..16 {
|
||||
let mut x = PointProjective::INFINITY;
|
||||
if i & 1 != 0 {
|
||||
x = &x + &g32;
|
||||
}
|
||||
if i & 2 != 0 {
|
||||
x = &x + &g96;
|
||||
}
|
||||
if i & 4 != 0 {
|
||||
x = &x + &g160;
|
||||
}
|
||||
if i & 8 != 0 {
|
||||
x = &x + &g224;
|
||||
}
|
||||
assert_eq!(PointProjective::from_affine(&precomputed(1, i - 1)), x);
|
||||
}
|
||||
}
|
||||
}
|
||||
154
libraries/crypto/src/ecdh.rs
Normal file
154
libraries/crypto/src/ecdh.rs
Normal file
@@ -0,0 +1,154 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::ec::exponent256::NonZeroExponentP256;
|
||||
use super::ec::int256;
|
||||
use super::ec::int256::Int256;
|
||||
use super::ec::point::PointP256;
|
||||
use super::rng256::Rng256;
|
||||
use super::sha256::Sha256;
|
||||
use super::Hash256;
|
||||
|
||||
pub const NBYTES: usize = int256::NBYTES;
|
||||
|
||||
pub struct SecKey {
|
||||
a: NonZeroExponentP256,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "derive_debug", derive(Clone, PartialEq, Debug))]
|
||||
pub struct PubKey {
|
||||
p: PointP256,
|
||||
}
|
||||
|
||||
impl SecKey {
|
||||
pub fn gensk<R>(rng: &mut R) -> SecKey
|
||||
where
|
||||
R: Rng256,
|
||||
{
|
||||
SecKey {
|
||||
a: NonZeroExponentP256::gen_uniform(rng),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn genpk(&self) -> PubKey {
|
||||
PubKey {
|
||||
p: PointP256::base_point_mul(self.a.as_exponent()),
|
||||
}
|
||||
}
|
||||
|
||||
fn exchange_raw(&self, other: &PubKey) -> PointP256 {
|
||||
// At this point, the PubKey type guarantees that other.p is a valid point on the curve.
|
||||
// It's the responsibility of the caller to handle errors when converting serialized bytes
|
||||
// to a PubKey.
|
||||
other.p.mul(self.a.as_exponent())
|
||||
// TODO: Do we need to check that the exchanged point is not infinite, and if yes handle
|
||||
// the error? The following argument should be reviewed:
|
||||
//
|
||||
// In principle this isn't needed on the P-256 curve, which has a prime order and a
|
||||
// cofactor of 1.
|
||||
//
|
||||
// Some pointers on this:
|
||||
// - https://www.secg.org/sec1-v2.pdf
|
||||
}
|
||||
|
||||
// DH key agreement method defined in the FIDO2 specification, Section 5.5.4. "Getting
|
||||
// sharedSecret from Authenticator"
|
||||
pub fn exchange_x_sha256(&self, other: &PubKey) -> [u8; 32] {
|
||||
let p = self.exchange_raw(other);
|
||||
let mut x: [u8; 32] = [Default::default(); 32];
|
||||
p.getx().to_int().to_bin(&mut x);
|
||||
Sha256::hash(&x)
|
||||
}
|
||||
}
|
||||
|
||||
impl PubKey {
|
||||
#[cfg(test)]
|
||||
fn from_bytes_uncompressed(bytes: &[u8]) -> Option<PubKey> {
|
||||
PointP256::from_bytes_uncompressed_vartime(bytes).map(|p| PubKey { p })
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn to_bytes_uncompressed(&self, bytes: &mut [u8; 65]) {
|
||||
self.p.to_bytes_uncompressed(bytes);
|
||||
}
|
||||
|
||||
pub fn from_coordinates(x: &[u8; NBYTES], y: &[u8; NBYTES]) -> Option<PubKey> {
|
||||
PointP256::new_checked_vartime(Int256::from_bin(x), Int256::from_bin(y))
|
||||
.map(|p| PubKey { p })
|
||||
}
|
||||
|
||||
pub fn to_coordinates(&self, x: &mut [u8; NBYTES], y: &mut [u8; NBYTES]) {
|
||||
self.p.getx().to_int().to_bin(x);
|
||||
self.p.gety().to_int().to_bin(y);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::rng256::ThreadRng256;
|
||||
use super::*;
|
||||
|
||||
// Run more test iterations in release mode, as the code should be faster.
|
||||
#[cfg(not(debug_assertions))]
|
||||
const ITERATIONS: u32 = 10000;
|
||||
#[cfg(debug_assertions)]
|
||||
const ITERATIONS: u32 = 1000;
|
||||
|
||||
/** Test that key generation creates valid keys **/
|
||||
#[test]
|
||||
fn test_gen_pub_is_valid_random() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
|
||||
for _ in 0..ITERATIONS {
|
||||
let sk = SecKey::gensk(&mut rng);
|
||||
let pk = sk.genpk();
|
||||
assert!(pk.p.is_valid_vartime());
|
||||
}
|
||||
}
|
||||
|
||||
/** Test that the exchanged key is the same on both sides **/
|
||||
#[test]
|
||||
fn test_exchange_x_sha256_is_symmetric() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
|
||||
for _ in 0..ITERATIONS {
|
||||
let sk_a = SecKey::gensk(&mut rng);
|
||||
let pk_a = sk_a.genpk();
|
||||
let sk_b = SecKey::gensk(&mut rng);
|
||||
let pk_b = sk_b.genpk();
|
||||
assert_eq!(sk_a.exchange_x_sha256(&pk_b), sk_b.exchange_x_sha256(&pk_a));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exchange_x_sha256_bytes_is_symmetric() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
|
||||
for _ in 0..ITERATIONS {
|
||||
let sk_a = SecKey::gensk(&mut rng);
|
||||
let mut pk_bytes_a = [Default::default(); 65];
|
||||
sk_a.genpk().to_bytes_uncompressed(&mut pk_bytes_a);
|
||||
|
||||
let sk_b = SecKey::gensk(&mut rng);
|
||||
let mut pk_bytes_b = [Default::default(); 65];
|
||||
sk_b.genpk().to_bytes_uncompressed(&mut pk_bytes_b);
|
||||
|
||||
let pk_a = PubKey::from_bytes_uncompressed(&pk_bytes_a).unwrap();
|
||||
let pk_b = PubKey::from_bytes_uncompressed(&pk_bytes_b).unwrap();
|
||||
assert_eq!(sk_a.exchange_x_sha256(&pk_b), sk_b.exchange_x_sha256(&pk_a));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: tests with invalid public shares.
|
||||
}
|
||||
643
libraries/crypto/src/ecdsa.rs
Normal file
643
libraries/crypto/src/ecdsa.rs
Normal file
@@ -0,0 +1,643 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::ec::exponent256::{ExponentP256, NonZeroExponentP256};
|
||||
use super::ec::int256;
|
||||
use super::ec::int256::Int256;
|
||||
use super::ec::point::PointP256;
|
||||
use super::hmac::hmac_256;
|
||||
use super::rng256::Rng256;
|
||||
use super::{Hash256, HashBlockSize64Bytes};
|
||||
use alloc::vec::Vec;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "derive_debug", derive(Debug))]
|
||||
pub struct SecKey {
|
||||
k: NonZeroExponentP256,
|
||||
}
|
||||
|
||||
pub struct Signature {
|
||||
r: NonZeroExponentP256,
|
||||
s: NonZeroExponentP256,
|
||||
}
|
||||
|
||||
pub struct PubKey {
|
||||
p: PointP256,
|
||||
}
|
||||
|
||||
impl SecKey {
|
||||
pub fn gensk<R>(rng: &mut R) -> SecKey
|
||||
where
|
||||
R: Rng256,
|
||||
{
|
||||
SecKey {
|
||||
k: NonZeroExponentP256::gen_uniform(rng),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn genpk(&self) -> PubKey {
|
||||
PubKey {
|
||||
p: PointP256::base_point_mul(self.k.as_exponent()),
|
||||
}
|
||||
}
|
||||
|
||||
// ECDSA signature based on a RNG to generate a suitable randomization parameter.
|
||||
// Under the hood, rejection sampling is used to make sure that the randomization parameter is
|
||||
// uniformly distributed.
|
||||
// The provided RNG must be cryptographically secure; otherwise this method is insecure.
|
||||
pub fn sign_rng<H, R>(&self, msg: &[u8], rng: &mut R) -> Signature
|
||||
where
|
||||
H: Hash256,
|
||||
R: Rng256,
|
||||
{
|
||||
let m = ExponentP256::modn(Int256::from_bin(&H::hash(msg)));
|
||||
|
||||
loop {
|
||||
let k = NonZeroExponentP256::gen_uniform(rng);
|
||||
if let Some(sign) = self.try_sign(&k, &m) {
|
||||
return sign;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deterministic ECDSA signature based on RFC 6979 to generate a suitable randomization
|
||||
// parameter.
|
||||
pub fn sign_rfc6979<H>(&self, msg: &[u8]) -> Signature
|
||||
where
|
||||
H: Hash256 + HashBlockSize64Bytes,
|
||||
{
|
||||
let m = ExponentP256::modn(Int256::from_bin(&H::hash(msg)));
|
||||
|
||||
let mut rfc_6979 = Rfc6979::<H>::new(self, &msg);
|
||||
loop {
|
||||
let k = NonZeroExponentP256::from_int_checked(rfc_6979.next());
|
||||
// The branching here is fine. By design the algorithm of RFC 6976 has a running time
|
||||
// that depends on the sequence of generated k.
|
||||
if bool::from(k.is_none()) {
|
||||
continue;
|
||||
}
|
||||
let k = k.unwrap();
|
||||
|
||||
if let Some(sign) = self.try_sign(&k, &m) {
|
||||
return sign;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try signing a curve element given a randomization parameter k. If no signature can be
|
||||
// obtained from this k, None is returned and the caller should try again with another value.
|
||||
fn try_sign(&self, k: &NonZeroExponentP256, msg: &ExponentP256) -> Option<Signature> {
|
||||
let r = ExponentP256::modn(PointP256::base_point_mul(k.as_exponent()).getx().to_int());
|
||||
// The branching here is fine because all this reveals is that k generated an unsuitable r.
|
||||
let r = r.non_zero();
|
||||
if bool::from(r.is_none()) {
|
||||
return None;
|
||||
}
|
||||
let r = r.unwrap();
|
||||
|
||||
let (s, top) = &(&r * &self.k).to_int() + &msg.to_int();
|
||||
let s = k.inv().as_exponent().mul_top(&s, top);
|
||||
|
||||
// The branching here is fine because all this reveals is that k generated an unsuitable s.
|
||||
let s = s.non_zero();
|
||||
if bool::from(s.is_none()) {
|
||||
return None;
|
||||
}
|
||||
let s = s.unwrap();
|
||||
|
||||
Some(Signature { r, s })
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn get_k_rfc6979<H>(&self, msg: &[u8]) -> NonZeroExponentP256
|
||||
where
|
||||
H: Hash256 + HashBlockSize64Bytes,
|
||||
{
|
||||
let m = ExponentP256::modn(Int256::from_bin(&H::hash(msg)));
|
||||
|
||||
let mut rfc_6979 = Rfc6979::<H>::new(self, &msg);
|
||||
loop {
|
||||
let k = NonZeroExponentP256::from_int_checked(rfc_6979.next());
|
||||
if bool::from(k.is_none()) {
|
||||
continue;
|
||||
}
|
||||
let k = k.unwrap();
|
||||
if self.try_sign(&k, &m).is_some() {
|
||||
return k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8; 32]) -> Option<SecKey> {
|
||||
let k = NonZeroExponentP256::from_int_checked(Int256::from_bin(bytes));
|
||||
// The branching here is fine because all this reveals is whether the key was invalid.
|
||||
if bool::from(k.is_none()) {
|
||||
return None;
|
||||
}
|
||||
let k = k.unwrap();
|
||||
Some(SecKey { k })
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self, bytes: &mut [u8; 32]) {
|
||||
self.k.to_int().to_bin(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
pub fn to_asn1_der(&self) -> Vec<u8> {
|
||||
const DER_INTEGER_TYPE: u8 = 0x02;
|
||||
const DER_DEF_LENGTH_SEQUENCE: u8 = 0x30;
|
||||
|
||||
let r_encoding = self.r.to_int().to_minimal_encoding();
|
||||
let s_encoding = self.s.to_int().to_minimal_encoding();
|
||||
// We rely on the encoding to be short enough such that
|
||||
// sum of lengths + 4 still fits into 7 bits.
|
||||
#[cfg(test)]
|
||||
assert!(r_encoding.len() <= 33);
|
||||
#[cfg(test)]
|
||||
assert!(s_encoding.len() <= 33);
|
||||
// The ASN1 of a signature is a two member sequence. Its length is the
|
||||
// sum of the integer encoding lengths and 2 header bytes per integer.
|
||||
let mut encoding = vec![
|
||||
DER_DEF_LENGTH_SEQUENCE,
|
||||
(r_encoding.len() + s_encoding.len() + 4) as u8,
|
||||
];
|
||||
encoding.push(DER_INTEGER_TYPE);
|
||||
encoding.push(r_encoding.len() as u8);
|
||||
encoding.extend(r_encoding);
|
||||
encoding.push(DER_INTEGER_TYPE);
|
||||
encoding.push(s_encoding.len() as u8);
|
||||
encoding.extend(s_encoding);
|
||||
encoding
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub fn from_bytes(bytes: &[u8]) -> Option<Signature> {
|
||||
if bytes.len() != 64 {
|
||||
None
|
||||
} else {
|
||||
let r =
|
||||
NonZeroExponentP256::from_int_checked(Int256::from_bin(array_ref![bytes, 0, 32]));
|
||||
let s =
|
||||
NonZeroExponentP256::from_int_checked(Int256::from_bin(array_ref![bytes, 32, 32]));
|
||||
if bool::from(r.is_none()) || bool::from(s.is_none()) {
|
||||
return None;
|
||||
}
|
||||
let r = r.unwrap();
|
||||
let s = s.unwrap();
|
||||
Some(Signature { r, s })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn to_bytes(&self, bytes: &mut [u8; 64]) {
|
||||
self.r.to_int().to_bin(array_mut_ref![bytes, 0, 32]);
|
||||
self.s.to_int().to_bin(array_mut_ref![bytes, 32, 32]);
|
||||
}
|
||||
}
|
||||
|
||||
impl PubKey {
|
||||
pub const ES256_ALGORITHM: i64 = -7;
|
||||
#[cfg(feature = "with_ctap1")]
|
||||
const UNCOMPRESSED_LENGTH: usize = 1 + 2 * int256::NBYTES;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub fn from_bytes_uncompressed(bytes: &[u8]) -> Option<PubKey> {
|
||||
PointP256::from_bytes_uncompressed_vartime(bytes).map(|p| PubKey { p })
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn to_bytes_uncompressed(&self, bytes: &mut [u8; 65]) {
|
||||
self.p.to_bytes_uncompressed(bytes);
|
||||
}
|
||||
|
||||
#[cfg(feature = "with_ctap1")]
|
||||
pub fn to_uncompressed(&self) -> [u8; PubKey::UNCOMPRESSED_LENGTH] {
|
||||
// Formatting according to:
|
||||
// https://tools.ietf.org/id/draft-jivsov-ecc-compact-05.html#overview
|
||||
const B0_BYTE_MARKER: u8 = 0x04;
|
||||
let mut representation = [0; PubKey::UNCOMPRESSED_LENGTH];
|
||||
let (marker, x, y) =
|
||||
mut_array_refs![&mut representation, 1, int256::NBYTES, int256::NBYTES];
|
||||
marker[0] = B0_BYTE_MARKER;
|
||||
self.p.getx().to_int().to_bin(x);
|
||||
self.p.gety().to_int().to_bin(y);
|
||||
representation
|
||||
}
|
||||
|
||||
// Encodes the key according to CBOR Object Signing and Encryption, defined in RFC 8152.
|
||||
pub fn to_cose_key(&self) -> Option<Vec<u8>> {
|
||||
const EC2_KEY_TYPE: i64 = 2;
|
||||
const P_256_CURVE: i64 = 1;
|
||||
let mut x_bytes = vec![0; int256::NBYTES];
|
||||
self.p
|
||||
.getx()
|
||||
.to_int()
|
||||
.to_bin(array_mut_ref![x_bytes.as_mut_slice(), 0, int256::NBYTES]);
|
||||
let x_byte_cbor: cbor::Value = cbor_bytes!(x_bytes);
|
||||
let mut y_bytes = vec![0; int256::NBYTES];
|
||||
self.p
|
||||
.gety()
|
||||
.to_int()
|
||||
.to_bin(array_mut_ref![y_bytes.as_mut_slice(), 0, int256::NBYTES]);
|
||||
let y_byte_cbor: cbor::Value = cbor_bytes!(y_bytes);
|
||||
let cbor_value = cbor_map_options! {
|
||||
1 => EC2_KEY_TYPE,
|
||||
3 => PubKey::ES256_ALGORITHM,
|
||||
-1 => P_256_CURVE,
|
||||
-2 => x_byte_cbor,
|
||||
-3 => y_byte_cbor,
|
||||
};
|
||||
let mut encoded_key = Vec::new();
|
||||
if cbor::write(cbor_value, &mut encoded_key) {
|
||||
Some(encoded_key)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub fn verify_vartime<H>(&self, msg: &[u8], sign: &Signature) -> bool
|
||||
where
|
||||
H: Hash256,
|
||||
{
|
||||
let m = ExponentP256::modn(Int256::from_bin(&H::hash(msg)));
|
||||
|
||||
let v = sign.s.inv();
|
||||
let u = &m * v.as_exponent();
|
||||
let v = &sign.r * &v;
|
||||
|
||||
let u = self.p.points_mul(&u, v.as_exponent()).getx();
|
||||
|
||||
ExponentP256::modn(u.to_int()) == *sign.r.as_exponent()
|
||||
}
|
||||
}
|
||||
|
||||
struct Rfc6979<H>
|
||||
where
|
||||
H: Hash256 + HashBlockSize64Bytes,
|
||||
{
|
||||
k: [u8; 32],
|
||||
v: [u8; 32],
|
||||
hash_marker: PhantomData<H>,
|
||||
}
|
||||
|
||||
impl<H> Rfc6979<H>
|
||||
where
|
||||
H: Hash256 + HashBlockSize64Bytes,
|
||||
{
|
||||
pub fn new(sk: &SecKey, msg: &[u8]) -> Rfc6979<H> {
|
||||
let h1 = H::hash(msg);
|
||||
let v = [0x01; 32];
|
||||
let k = [0x00; 32];
|
||||
|
||||
let mut contents = [0; 3 * 32 + 1];
|
||||
let (contents_v, marker, contents_k, contents_h1) =
|
||||
mut_array_refs![&mut contents, 32, 1, 32, 32];
|
||||
contents_v.copy_from_slice(&v);
|
||||
marker[0] = 0x00;
|
||||
Int256::to_bin(&sk.k.to_int(), contents_k);
|
||||
Int256::to_bin(&Int256::from_bin(&h1).modd(&Int256::N), contents_h1);
|
||||
|
||||
let k = hmac_256::<H>(&k, &contents);
|
||||
let v = hmac_256::<H>(&k, &v);
|
||||
|
||||
let (contents_v, marker, _) = mut_array_refs![&mut contents, 32, 1, 64];
|
||||
contents_v.copy_from_slice(&v);
|
||||
marker[0] = 0x01;
|
||||
|
||||
let k = hmac_256::<H>(&k, &contents);
|
||||
let v = hmac_256::<H>(&k, &v);
|
||||
|
||||
Rfc6979 {
|
||||
k,
|
||||
v,
|
||||
hash_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn next(&mut self) -> Int256 {
|
||||
// Note: at this step, the logic from RFC 6979 is simplified, because the HMAC produces 256
|
||||
// bits and we need 256 bits.
|
||||
let t = hmac_256::<H>(&self.k, &self.v);
|
||||
let result = Int256::from_bin(&t);
|
||||
|
||||
let mut v1 = [0; 33];
|
||||
v1[..32].copy_from_slice(&self.v);
|
||||
v1[32] = 0x00;
|
||||
self.k = hmac_256::<H>(&self.k, &v1);
|
||||
self.v = hmac_256::<H>(&self.k, &self.v);
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::rng256::ThreadRng256;
|
||||
use super::super::sha256::Sha256;
|
||||
use super::*;
|
||||
extern crate hex;
|
||||
extern crate ring;
|
||||
extern crate untrusted;
|
||||
|
||||
// Run more test iterations in release mode, as the code should be faster.
|
||||
#[cfg(not(debug_assertions))]
|
||||
const ITERATIONS: u32 = 10000;
|
||||
#[cfg(debug_assertions)]
|
||||
const ITERATIONS: u32 = 1000;
|
||||
|
||||
/** Test that key generation creates valid keys **/
|
||||
#[test]
|
||||
fn test_genpk_is_valid_random() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
|
||||
for _ in 0..ITERATIONS {
|
||||
let sk = SecKey::gensk(&mut rng);
|
||||
let pk = sk.genpk();
|
||||
assert!(pk.p.is_valid_vartime());
|
||||
}
|
||||
}
|
||||
|
||||
/** Serialization **/
|
||||
#[test]
|
||||
fn test_seckey_to_bytes_from_bytes() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
|
||||
for _ in 0..ITERATIONS {
|
||||
let sk = SecKey::gensk(&mut rng);
|
||||
let mut bytes = [0; 32];
|
||||
sk.to_bytes(&mut bytes);
|
||||
let decoded_sk = SecKey::from_bytes(&bytes);
|
||||
assert_eq!(decoded_sk, Some(sk));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seckey_from_bytes_zero() {
|
||||
// Zero is not a valid exponent for a secret key.
|
||||
let bytes = [0; 32];
|
||||
let sk = SecKey::from_bytes(&bytes);
|
||||
assert!(sk.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seckey_from_bytes_n() {
|
||||
let mut bytes = [0; 32];
|
||||
Int256::N.to_bin(&mut bytes);
|
||||
let sk = SecKey::from_bytes(&bytes);
|
||||
assert!(sk.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seckey_from_bytes_ge_n() {
|
||||
let bytes = [0xFF; 32];
|
||||
let sk = SecKey::from_bytes(&bytes);
|
||||
assert!(sk.is_none());
|
||||
}
|
||||
|
||||
/** Test vectors from RFC6979 **/
|
||||
fn int256_from_hex(x: &str) -> Int256 {
|
||||
let bytes = hex::decode(x).unwrap();
|
||||
assert_eq!(bytes.len(), 32);
|
||||
Int256::from_bin(array_ref![bytes.as_slice(), 0, 32])
|
||||
}
|
||||
|
||||
// Test vectors from RFC6979, Section A.2.5.
|
||||
const RFC6979_X: &str = "C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721";
|
||||
const RFC6979_UX: &str = "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6";
|
||||
const RFC6979_UY: &str = "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299";
|
||||
|
||||
#[test]
|
||||
fn test_rfc6979_keypair() {
|
||||
let sk = SecKey {
|
||||
k: NonZeroExponentP256::from_int_checked(int256_from_hex(RFC6979_X)).unwrap(),
|
||||
};
|
||||
let pk = sk.genpk();
|
||||
assert_eq!(pk.p.getx().to_int(), int256_from_hex(RFC6979_UX));
|
||||
assert_eq!(pk.p.gety().to_int(), int256_from_hex(RFC6979_UY));
|
||||
}
|
||||
|
||||
fn test_rfc6979(msg: &str, k: &str, r: &str, s: &str) {
|
||||
let sk = SecKey {
|
||||
k: NonZeroExponentP256::from_int_checked(int256_from_hex(RFC6979_X)).unwrap(),
|
||||
};
|
||||
assert_eq!(
|
||||
sk.get_k_rfc6979::<Sha256>(msg.as_bytes()).to_int(),
|
||||
int256_from_hex(k)
|
||||
);
|
||||
let sign = sk.sign_rfc6979::<Sha256>(msg.as_bytes());
|
||||
assert_eq!(sign.r.to_int(), int256_from_hex(r));
|
||||
assert_eq!(sign.s.to_int(), int256_from_hex(s));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rfc6979_sample() {
|
||||
let msg = "sample";
|
||||
let k = "A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60";
|
||||
let r = "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716";
|
||||
let s = "F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8";
|
||||
test_rfc6979(msg, k, r, s);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rfc6979_test() {
|
||||
let msg = "test";
|
||||
let k = "D16B6AE827F17175E040871A1C7EC3500192C4C92677336EC2537ACAEE0008E0";
|
||||
let r = "F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367";
|
||||
let s = "019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083";
|
||||
test_rfc6979(msg, k, r, s);
|
||||
}
|
||||
|
||||
/** Tests that sign and verify are consistent **/
|
||||
// Test that signed messages are correctly verified.
|
||||
#[test]
|
||||
fn test_sign_rfc6979_verify_random() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
|
||||
for _ in 0..ITERATIONS {
|
||||
let msg = rng.gen_uniform_u8x32();
|
||||
let sk = SecKey::gensk(&mut rng);
|
||||
let pk = sk.genpk();
|
||||
let sign = sk.sign_rfc6979::<Sha256>(&msg);
|
||||
assert!(pk.verify_vartime::<Sha256>(&msg, &sign));
|
||||
}
|
||||
}
|
||||
|
||||
// Test that signed messages are correctly verified.
|
||||
#[test]
|
||||
fn test_sign_verify_random() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
|
||||
for _ in 0..ITERATIONS {
|
||||
let msg = rng.gen_uniform_u8x32();
|
||||
let sk = SecKey::gensk(&mut rng);
|
||||
let pk = sk.genpk();
|
||||
let sign = sk.sign_rng::<Sha256, _>(&msg, &mut rng);
|
||||
assert!(pk.verify_vartime::<Sha256>(&msg, &sign));
|
||||
}
|
||||
}
|
||||
|
||||
/** Tests that this code is compatible with the ring crate **/
|
||||
// Test that the ring crate works properly.
|
||||
#[test]
|
||||
fn test_ring_sign_ring_verify() {
|
||||
use ring::rand::SecureRandom;
|
||||
use ring::signature::KeyPair;
|
||||
|
||||
let ring_rng = ring::rand::SystemRandom::new();
|
||||
|
||||
for _ in 0..ITERATIONS {
|
||||
let mut msg_bytes: [u8; 64] = [Default::default(); 64];
|
||||
ring_rng.fill(&mut msg_bytes).unwrap();
|
||||
let msg = untrusted::Input::from(&msg_bytes);
|
||||
|
||||
let pkcs8_bytes = ring::signature::EcdsaKeyPair::generate_pkcs8(
|
||||
&ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING,
|
||||
&ring_rng,
|
||||
)
|
||||
.unwrap();
|
||||
let key_pair = ring::signature::EcdsaKeyPair::from_pkcs8(
|
||||
&ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING,
|
||||
untrusted::Input::from(pkcs8_bytes.as_ref()),
|
||||
)
|
||||
.unwrap();
|
||||
let public_key_bytes = key_pair.public_key().as_ref();
|
||||
|
||||
let sig = key_pair.sign(&ring_rng, msg).unwrap();
|
||||
let sig_bytes = sig.as_ref();
|
||||
|
||||
assert!(ring::signature::verify(
|
||||
&ring::signature::ECDSA_P256_SHA256_FIXED,
|
||||
untrusted::Input::from(public_key_bytes),
|
||||
msg,
|
||||
untrusted::Input::from(sig_bytes)
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
// Test that messages signed by the ring crate are correctly verified by this code.
|
||||
#[test]
|
||||
fn test_ring_sign_self_verify() {
|
||||
use ring::rand::SecureRandom;
|
||||
use ring::signature::KeyPair;
|
||||
|
||||
let ring_rng = ring::rand::SystemRandom::new();
|
||||
|
||||
for _ in 0..ITERATIONS {
|
||||
let mut msg_bytes: [u8; 64] = [Default::default(); 64];
|
||||
ring_rng.fill(&mut msg_bytes).unwrap();
|
||||
|
||||
let pkcs8_bytes = ring::signature::EcdsaKeyPair::generate_pkcs8(
|
||||
&ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING,
|
||||
&ring_rng,
|
||||
)
|
||||
.unwrap();
|
||||
let key_pair = ring::signature::EcdsaKeyPair::from_pkcs8(
|
||||
&ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING,
|
||||
untrusted::Input::from(pkcs8_bytes.as_ref()),
|
||||
)
|
||||
.unwrap();
|
||||
let public_key_bytes = key_pair.public_key().as_ref();
|
||||
|
||||
let sig = key_pair
|
||||
.sign(&ring_rng, untrusted::Input::from(&msg_bytes))
|
||||
.unwrap();
|
||||
let sig_bytes = sig.as_ref();
|
||||
|
||||
let pk = PubKey::from_bytes_uncompressed(public_key_bytes).unwrap();
|
||||
let sign = Signature::from_bytes(sig_bytes).unwrap();
|
||||
assert!(pk.verify_vartime::<Sha256>(&msg_bytes, &sign));
|
||||
}
|
||||
}
|
||||
|
||||
// Test that messages signed by this code are correctly verified by the ring crate.
|
||||
#[test]
|
||||
fn test_self_sign_ring_verify() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
|
||||
for _ in 0..ITERATIONS {
|
||||
let msg_bytes = rng.gen_uniform_u8x32();
|
||||
let sk = SecKey::gensk(&mut rng);
|
||||
let pk = sk.genpk();
|
||||
let sign = sk.sign_rng::<Sha256, _>(&msg_bytes, &mut rng);
|
||||
|
||||
let mut public_key_bytes: [u8; 65] = [Default::default(); 65];
|
||||
pk.to_bytes_uncompressed(&mut public_key_bytes);
|
||||
let mut sig_bytes: [u8; 64] = [Default::default(); 64];
|
||||
sign.to_bytes(&mut sig_bytes);
|
||||
|
||||
assert!(ring::signature::verify(
|
||||
&ring::signature::ECDSA_P256_SHA256_FIXED,
|
||||
untrusted::Input::from(&public_key_bytes),
|
||||
untrusted::Input::from(&msg_bytes),
|
||||
untrusted::Input::from(&sig_bytes)
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signature_to_asn1_der_short_encodings() {
|
||||
let r_bytes = [
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01,
|
||||
];
|
||||
let r = NonZeroExponentP256::from_int_checked(Int256::from_bin(&r_bytes)).unwrap();
|
||||
let s_bytes = [
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF,
|
||||
];
|
||||
let s = NonZeroExponentP256::from_int_checked(Int256::from_bin(&s_bytes)).unwrap();
|
||||
let signature = Signature { r, s };
|
||||
let expected_encoding = vec![0x30, 0x07, 0x02, 0x01, 0x01, 0x02, 0x02, 0x00, 0xFF];
|
||||
|
||||
assert_eq!(signature.to_asn1_der(), expected_encoding);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signature_to_asn1_der_long_encodings() {
|
||||
let r_bytes = [
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA,
|
||||
];
|
||||
let r = NonZeroExponentP256::from_int_checked(Int256::from_bin(&r_bytes)).unwrap();
|
||||
let s_bytes = [
|
||||
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
|
||||
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
|
||||
0xBB, 0xBB, 0xBB, 0xBB,
|
||||
];
|
||||
let s = NonZeroExponentP256::from_int_checked(Int256::from_bin(&s_bytes)).unwrap();
|
||||
let signature = Signature { r, s };
|
||||
let expected_encoding = vec![
|
||||
0x30, 0x46, 0x02, 0x21, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x02, 0x21, 0x00, 0xBB, 0xBB,
|
||||
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
|
||||
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
|
||||
0xBB, 0xBB,
|
||||
];
|
||||
|
||||
assert_eq!(signature.to_asn1_der(), expected_encoding);
|
||||
}
|
||||
|
||||
// TODO: Test edge-cases and compare the behavior with ring.
|
||||
// - Invalid public key (at infinity, values not less than the prime p), but ring doesn't
|
||||
// directly exposes key validation in its API.
|
||||
}
|
||||
281
libraries/crypto/src/hmac.rs
Normal file
281
libraries/crypto/src/hmac.rs
Normal file
@@ -0,0 +1,281 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::{Hash256, HashBlockSize64Bytes};
|
||||
use subtle::ConstantTimeEq;
|
||||
|
||||
const BLOCK_SIZE: usize = 64;
|
||||
const HASH_SIZE: usize = 32;
|
||||
|
||||
pub fn verify_hmac_256<H>(key: &[u8], contents: &[u8], mac: &[u8; HASH_SIZE]) -> bool
|
||||
where
|
||||
H: Hash256 + HashBlockSize64Bytes,
|
||||
{
|
||||
let expected_mac = hmac_256::<H>(key, contents);
|
||||
bool::from(expected_mac.ct_eq(mac))
|
||||
}
|
||||
|
||||
// FIDO2's PIN verification is just matching the first 16 bytes of the HMAC
|
||||
// against the pin ¯\_(ツ)_/¯
|
||||
pub fn verify_hmac_256_first_128bits<H>(key: &[u8], contents: &[u8], pin: &[u8; 16]) -> bool
|
||||
where
|
||||
H: Hash256 + HashBlockSize64Bytes,
|
||||
{
|
||||
let expected_mac = hmac_256::<H>(key, contents);
|
||||
bool::from(array_ref![expected_mac, 0, 16].ct_eq(pin))
|
||||
}
|
||||
|
||||
pub fn hmac_256<H>(key: &[u8], contents: &[u8]) -> [u8; HASH_SIZE]
|
||||
where
|
||||
H: Hash256 + HashBlockSize64Bytes,
|
||||
{
|
||||
let mut ipad: [u8; BLOCK_SIZE] = [0x36; BLOCK_SIZE];
|
||||
let mut opad: [u8; BLOCK_SIZE] = [0x5c; BLOCK_SIZE];
|
||||
if key.len() <= BLOCK_SIZE {
|
||||
xor_pads(&mut ipad, &mut opad, key);
|
||||
} else {
|
||||
xor_pads(&mut ipad, &mut opad, &H::hash(key));
|
||||
}
|
||||
|
||||
let mut ihasher = H::new();
|
||||
ihasher.update(&ipad);
|
||||
ihasher.update(contents);
|
||||
let ihash = ihasher.finalize();
|
||||
|
||||
let mut ohasher = H::new();
|
||||
ohasher.update(&opad);
|
||||
ohasher.update(&ihash);
|
||||
|
||||
ohasher.finalize()
|
||||
}
|
||||
|
||||
fn xor_pads(ipad: &mut [u8; BLOCK_SIZE], opad: &mut [u8; BLOCK_SIZE], key: &[u8]) {
|
||||
for (i, k) in key.iter().enumerate() {
|
||||
ipad[i] ^= k;
|
||||
opad[i] ^= k;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::sha256::Sha256;
|
||||
use super::*;
|
||||
extern crate hex;
|
||||
|
||||
#[test]
|
||||
fn test_verify_hmac_valid() {
|
||||
// Test for various lengths of the key and contents.
|
||||
for len in 0..128 {
|
||||
let key = vec![0; len];
|
||||
let contents = vec![0; len];
|
||||
let mac = hmac_256::<Sha256>(&key, &contents);
|
||||
assert!(verify_hmac_256::<Sha256>(&key, &contents, &mac));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verify_hmac_invalid() {
|
||||
// Test for various lengths of the key and contents.
|
||||
for len in 0..128 {
|
||||
let key = vec![0; len];
|
||||
let contents = vec![0; len];
|
||||
let mac = hmac_256::<Sha256>(&key, &contents);
|
||||
|
||||
// Check that invalid MACs don't verify, by changing any byte of the valid MAC.
|
||||
for i in 0..HASH_SIZE {
|
||||
let mut bad_mac = mac;
|
||||
bad_mac[i] ^= 0x01;
|
||||
assert!(!verify_hmac_256::<Sha256>(&key, &contents, &bad_mac));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hmac_sha256_empty() {
|
||||
let mut buf = [0; 96];
|
||||
buf[..64].copy_from_slice(&[0x5c; 64]);
|
||||
buf[64..].copy_from_slice(&Sha256::hash(&[0x36; 64]));
|
||||
assert_eq!(hmac_256::<Sha256>(&[], &[]), Sha256::hash(&buf));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hmac_sha256_examples() {
|
||||
assert_eq!(
|
||||
hmac_256::<Sha256>(&[], &[]),
|
||||
hex::decode("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad")
|
||||
.unwrap()
|
||||
.as_slice()
|
||||
);
|
||||
assert_eq!(
|
||||
hmac_256::<Sha256>(b"key", b"The quick brown fox jumps over the lazy dog"),
|
||||
hex::decode("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8")
|
||||
.unwrap()
|
||||
.as_slice()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash_sha256_for_various_lengths() {
|
||||
// This test makes sure that the key hashing and hash padding are implemented properly.
|
||||
//
|
||||
// Test vectors generated with the following Python script:
|
||||
//
|
||||
// import hashlib
|
||||
// import hmac
|
||||
// for n in range(128):
|
||||
// print('b"' + hmac.new('A' * n, 'A' * n, hashlib.sha256).hexdigest() + '",')
|
||||
//
|
||||
let hashes: [&[u8; 64]; 128] = [
|
||||
b"b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad",
|
||||
b"ff333794c5afd126a4e75aef1a35595a846e9e1d4053017d78d7aa3d8373182a",
|
||||
b"7c1d0c177d40e7fa03cd1fa9cfc314888985aecde8f586edfb05e71e5f109c20",
|
||||
b"8f7afbaef39ad155ba09bcbb386a08257731fc06fb2c1d3cff451af5386c0e7d",
|
||||
b"a4dbd2915084ba3bed9306ba674c1eb22fae1dffd971c95b62ab17f0711480cd",
|
||||
b"f59d521db107b4265d995f197b189de468b984816d2a01dc8ca3fcfc24d6ff37",
|
||||
b"29e0656a90f3975e41c8b7e55d225353c3bb8bc0b36328c8066a61763df70b83",
|
||||
b"25a85cdd13b683f3cac732fa1f19757afffe7013ddbea6e441af883379bf4232",
|
||||
b"5d0b0812ecb57fb4be7f29a8978cc4f2c35b32417cc9854e2702f7fb08f6d84d",
|
||||
b"d5e12df428ebd9d991a280c714c9197b977520a7fea87200177cf03618868cb3",
|
||||
b"fa311e0cd19106ab33f8ee84cafdc2f03be787679c1fe7b6e64df2b2e7466ca2",
|
||||
b"9a481f04a2f40d561e8e6c4850498699b36e915993153e9f9b5a4485cb0541b1",
|
||||
b"c8ae9a117e3a5c9125cc21c7f9df09de50de1a6846caf13586d1e5efdfcc1ce6",
|
||||
b"5ef3a488aaffb5db9173ef59e65c2dd27f4cd1a10e1b464ef5bf82d2e35eddd5",
|
||||
b"e5753e8febbb38a97c1dfee23a6103fc58416b7172bab834fe5684b00800abd5",
|
||||
b"0ed714c729a3db2ffde2c4ccb9f5da498c5a73a2c7010d463a7b5da8d18127aa",
|
||||
b"950918cfdb0cb20f327ba0b5095d53c0befb66b9f639d389020453fcf18e8c40",
|
||||
b"699470b9775ec45e9024394e7ebb16463534ed7a617bafddca11a3a0e61a3694",
|
||||
b"95e8c0520fc4dc4c85e00e3868c16ab22a82e8c71ca8ea329ae1ecef0ee3968a",
|
||||
b"7964fba6a123164167cbf51dc2c53948e13b2fee67d09f532e8b7bc56447c091",
|
||||
b"c7d07a5f715b3ea44c258de03f2000ba79a44dd8213feb6e6006e1c3becbedff",
|
||||
b"3eb1a7bf7e4f5c2d9b8cc12667ada8d7773cb9e9424104a30063778567df9422",
|
||||
b"19cc344ad67db96ea936ef15cc751b29fa0409f5c9894d2cfeb100d604653ffc",
|
||||
b"91001e472df16d68ee8033cd13d76a26543ccdfe1426cc6e969759b05ee7d115",
|
||||
b"65f1f4670f8537f37263dabedce049b0e7d1e71f741781413cc2d5c81ecd6ac3",
|
||||
b"0cf5de0ada8b717296a34fc386a8b77f60b607a48a899bee37650891a616dae7",
|
||||
b"de3d56f0c83c992163aac087c999ed8eb5a039f21b0536a1967e747868dafd56",
|
||||
b"0bc3fd1d46d2dc4e2d357d1f6b437d168051d6f19975223505fc2d0abddc3faa",
|
||||
b"1e30596f4144ca58f3e306548cd079cc92a51ab825a4ad3246393c22283af640",
|
||||
b"c2fbc726bf3eb7f0216c7e1d5f5b475a93b033b3f901a4a4dca6bbefc65b68b2",
|
||||
b"1c4ef56d530bb8b627df49ea7b31cf9520e067a2fd0c671896103e146dd4564a",
|
||||
b"9aeed0f7808bd6c13ce54aa5724484f41bd7cbb5e39fd1d7730befbbf056a957",
|
||||
b"e58aa85e83553b7fec841cbaf42cede943b6b7ded22661cd3b1867effe91b745",
|
||||
b"790fc5689193ac57c97dd25729003f2a0d8d3e5f9d2a39e007b794282a51cd3e",
|
||||
b"be067b95a45cdc0060d2c3757597d8d9b858128435e93346c28ce2e82a68e951",
|
||||
b"8734f497f5cd2c8667c7d8e1c2328e7e11fa80fc26c7d933937490d37718871f",
|
||||
b"e8a2d0e77dfad5b046bcff0340a975300b051a21ac403dd802348511a80ba8c8",
|
||||
b"4afec38787117ab6e71c34a4be7575643d8e74fc16b9d5666157fd9aee0f6e86",
|
||||
b"ac8b2831d636384d1d3ff5dd77b249860bd88d5aa9af3e1d4ee70be2a1b03db9",
|
||||
b"e92e1ab3934d3ed2073973204aaba03de3bc4e864cc74677b560c42971b26ab1",
|
||||
b"312effff0c19cf410b9e227654211133f29276c781baadbe00a1e8319e06e361",
|
||||
b"d46158da3c64439f8f176fd5e3d5ac59dcaa6c0835715c5ef30abedf34b13c59",
|
||||
b"693d18266ec508515b9a3839e5336918d41ec7891feadd684b49c03093bd2061",
|
||||
b"440b6a14be7bc2a1ec475a197fe4bea720d1214883e4d1e2029cf0f75fcdba29",
|
||||
b"ca8e30319508df21a851a06f543f59bf6fd3b241e5a52b36fb674b0d9d5e8f67",
|
||||
b"fa4f327635ff5c7051d6968daf5ffcc827bbd0da1e1c56d59918895bc418be98",
|
||||
b"0e6d0dd75bc42aa6e245a212ff027bc701a7ef61179b335365a29f545bcf45e0",
|
||||
b"57a08bef7822c2111ac79062240e725611322543f10758763c1c6467021c4fe7",
|
||||
b"29768d5fb640a46e0129303128669eb3c7fb357ef1c49506f6300cc8e451d5e2",
|
||||
b"009a868f1065ccb4227dc28084484263495ad90378dc928fc61d361eef2d072e",
|
||||
b"6808e39e343af0fd53309fc02b05da1a0e68b87d5cd434e94521c635a78d7fdb",
|
||||
b"8fe1668eba03be5444e0956396ac9d81ac1c4a7beb6a01151ad679f5ca0cd206",
|
||||
b"01f41c1cc6d9d260ec3d938d681fc476415aae96a318862a492ba1a56f1b0a88",
|
||||
b"3100bc758eeccb959376b334f999a2b4e5fcced5b5d4956510a86b654f1f0c04",
|
||||
b"6225330aedced9909d4a190dba55e807624f44e7c6e0c50cac5e4ccf8e2e0029",
|
||||
b"783111276f7218e3e525c83cdf117e2d5ce251f6a04beabb65ef565f513a9301",
|
||||
b"4b365ab05720ad517f46df03ff441f9e0769a2ce5279663b7d90eb7d980625ef",
|
||||
b"52431871c39a881c63df82860e32ccf05c1addbc630aaa580733f2e6a2fff5a6",
|
||||
b"f017486486b0e308a10862e910f22545c29670daa26bf0c6791827a7f9f625a4",
|
||||
b"85efd1eface951759a4642e882d0ef8d0be58afd483e0945d03a7a35fac789ac",
|
||||
b"880872df19c7ff14105ba59cebc07d9e9d7e67f4896a14acae5346c66c6ce2da",
|
||||
b"85ba2aa3634c619d604a964d62ae3c97f9eba7fcb7e4db2ebfa2bd23338c2d60",
|
||||
b"5aa9736d405016676878fcc63e84b286cfbc843799ea786d089b2200281d5a5c",
|
||||
b"30f43d84f3d5ffac60323a126fe321c6cc1e9c440249a8d69abe172494cba7ae",
|
||||
b"7dce62ce40f8f4cda666341730e7dfcde8839eed4236c58ae273e6687d229d85",
|
||||
b"83d670a41779f63fad0ece766a19920e0cfdd9d02f5a5900c888de21f6ae0526",
|
||||
b"bb2acf0d6d39e58b09204dedcc2fe68ad829ba471a077e6e03246d8a0b0c0858",
|
||||
b"1f94db9ee970a9fcc9089865eb2aa485765345f6d4de54815507ce363bc20711",
|
||||
b"b4bceedc935c574935117f7ad280a7d858da7ca5a6b0920b4975111206fcac77",
|
||||
b"b9da394c337e9aa150c12e54c574978773ff953270f5aefde88a766e9874c260",
|
||||
b"1769fcb5d31c8c09868e4e3dcd9db92b4cccefb5660e72bfc52159fda9da8518",
|
||||
b"d8ceb568f85e30cb48cabf8e84d577369033511cbbdac6a7996cf9f397c2e203",
|
||||
b"64c35795b87cbb02afcdc6a5e6bacb10d98cdd1bd810ccf12c847fbdcf4d2634",
|
||||
b"76ccd4e2b71a826128b60bc9fe33613d82f0ae1f57fa192f107ed54d25a842e0",
|
||||
b"095450e0f61a4201bb2197371247bb7ced09056d86e901202ecc561c3568e032",
|
||||
b"0e928f8e201fd3019f11037bf164cc3d719ecf08e6eac985f429702c41f25d0a",
|
||||
b"135f37174ff19409cef67f3263511ed9286901090eec2b54d9444036308a72cf",
|
||||
b"51eafe6978c32396022a31230b8b9120ac7bd79ad7a3303e6b6979063275c9b8",
|
||||
b"fd2fb9443156429b2bc042248bf022f18ee6ed11fefea222893c49e8fef6a17e",
|
||||
b"ed9a240e63644aa55c71fb339d79e1a38de71002c30baf14af38359c513de2e0",
|
||||
b"c925e74d4740558277a55fe57ba88ed05ce8f5d5c35c19e7228adc09351ecfa4",
|
||||
b"cd99660a7c2aded095152bc6d5fa160077355819fbf421acb95ab39ad8c27862",
|
||||
b"42cf7593a535a1e79299c2839f4e0ffba5b429cb0df6c77d3fe86b6a1535d505",
|
||||
b"348c6014dcb0cd583862c09ad24aa5d93e81e2f6ca4b04f4e77e50067f34e625",
|
||||
b"8b00c1d89bd10b24bda2c8f6e45c4112112baacab29d0330b377d811a7b0184e",
|
||||
b"dfe3960732f8e5958085a581859f6ccf40169df965bb8ff5feb4b0229a02c6f8",
|
||||
b"de0aa4189c97d17df38c0ea3bc9376287076939afd515336d5d7d851f81f2517",
|
||||
b"543190454858ff5396a1de3f753f84bdd2869fd2b59e3a89f090ce06bd94d626",
|
||||
b"541ddbe00a0237c5c8bd043e6cced9ce78209dd83b057272cd46c2cc2f39a88c",
|
||||
b"11c82017445f7e295d4c734a40cf28793df855dd321d507d4a0f3e212293ca2b",
|
||||
b"cda1ecd6ca2f3858352985b4833170589e17e1f7f464e279cc78051911b8e8d3",
|
||||
b"5feb471949318b26898b3339ac7a66e464a752223cf764aa0af9292fe087c39a",
|
||||
b"eb48e5de63ecd22f7b305c7e74ce8cc714ab858cf834cf485727868e017e473e",
|
||||
b"03428482b5208a35032777c7d628a6c8f3b07c5c87c641ddfb3adf46ffefe449",
|
||||
b"a8e0cd1dfcf6e1a29ba032d3889fca2f25e3fad1a9b1c36e4978e48945b06092",
|
||||
b"6cf4280b75da3bb22ddee9a9a3fdd1d0cd04627c00f73b608e44be9ce84869db",
|
||||
b"9fa7648f23c405938b6fb8eaf6a24c476dafd05625a9a8f6c52e1abb9d432a76",
|
||||
b"2906f0a6276e9a1ba4fbca2f335d9f7d3c331684814ac5407145d86891ba37f7",
|
||||
b"1b667ee18a909e3f828f2bd6a162e3aa1361f3801b7cbc863b1b54a1ccfbf580",
|
||||
b"a75e75962b3f950f7718839ef06cc09112806dbf88b142e369cf1ef99069c226",
|
||||
b"71b2e2f6d66f13b919a842843b201c25249ff4b4caa4c7ab079b2980de8a18f6",
|
||||
b"c4a9e73df196f876f5a3af1c8836504ee61daac5d9e15cc043a511310c22ddd8",
|
||||
b"88e3303a6a2ab03430652fea942ae7cd96618fae4addcf8e92989d542777e496",
|
||||
b"9a727095299564e2f5e1598f1a4095a2a000cb9196fe4eb13447932af777be3c",
|
||||
b"5643a1c72b189d462236a43afc7d0b9504cbf81b4fa9a6c9cca49bd50da299df",
|
||||
b"caebc47e2204fe19e757372c2e0469a34051415a09c927e63be7747903d80af5",
|
||||
b"e5c9fd4bd27e7a55958cb5f66ff88baf80ab40d9690e81a9cf03ada5bd08cd44",
|
||||
b"dc606eb9a631ca3f080f6d6f610444201608f47b5b49c75c2c0ec03ba9000009",
|
||||
b"bce230b32a7dc676fb98a4a3d41c4171e9e173e840b92c194fb1dc4accc079b9",
|
||||
b"51542ff3b57cd2ff6b1542649f7a44dbed32194b98c3af32b6ff3eefe6b490cf",
|
||||
b"703f5dea8c9e3ed75c691fc17699b9648a65a331add554fa3613ddcb7267565a",
|
||||
b"d74f9f60763467ce0b35ced0630ecf58605da0ca49e058de21524b5c532b5de8",
|
||||
b"e9dacaf1fefaad6d9d372affab8fb5216004fb3fa7a9b86b25ecd00e583c22a5",
|
||||
b"abe2c75f1ac881b743da99c543506c4b7532f3fc445fa8cbf1df22689770d66a",
|
||||
b"7be506d2fd6dc79f0b14ddfff0147c79d78d99140547efcd03d0a73819b84c5a",
|
||||
b"78dbc5c946ee8aa147ccfa8b5d9231c95c4257d8c79bd219ab95d53303367309",
|
||||
b"1d75ee600f2ba216d211189493d793aa610aa57ccbfc4d9a7f44194e7166a062",
|
||||
b"368a4d0ae1b139d71f35ba5f917a7ad4c18e6aa51b095cb135193dcd09e299b4",
|
||||
b"a9d3202db927be8f0d15d2dfb83ea09db32fec3b1fc10a6acfb91da8c3c5eaf3",
|
||||
b"c2284f8efeee554cc29a8802aadd7cd88e84561d353282ee31322ed497a3336c",
|
||||
b"7695648a111e2ea51013f03c9de91d81a2435a7777f303e51d027750f8381680",
|
||||
b"719fc44e0f64f7da9ac5d33d9ca912fdc839bb4535c66a21f0804f2cdf800666",
|
||||
b"6940c082413b0c1ced6f9cb6583588c472ff72b48b00a4fb6d2710d7ac4dad99",
|
||||
b"af1f26fcf070d9f5926dd41db3c09ec6b4c3f2208775cf983330cd0ff5aa239e",
|
||||
b"ae50df4404a7f46146d8112bfb1cde876e591abe5ef1640e27c4d178a84b6335",
|
||||
b"50f91f48df7f0f96af954be7e1b518bac537173cea38be300d98761da1d9b10f",
|
||||
b"9c9aee382b3e3417e87352bdcb48837e88335e9dd0112fc22ecf61e766a6ac43",
|
||||
b"d53cee1696c613f988520cf9c923c7cb6e6933b4faf57e640867d5f45a0f2569",
|
||||
];
|
||||
|
||||
let mut input = Vec::new();
|
||||
for i in 0..128 {
|
||||
assert_eq!(
|
||||
hmac_256::<Sha256>(&input, &input),
|
||||
hex::decode(hashes[i] as &[u8]).unwrap().as_slice()
|
||||
);
|
||||
input.push(b'A');
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: more tests
|
||||
}
|
||||
67
libraries/crypto/src/lib.rs
Normal file
67
libraries/crypto/src/lib.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![feature(wrapping_int_impl)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
extern crate subtle;
|
||||
#[macro_use]
|
||||
extern crate arrayref;
|
||||
extern crate byteorder;
|
||||
extern crate libtock;
|
||||
#[macro_use]
|
||||
extern crate cbor;
|
||||
|
||||
pub mod aes256;
|
||||
pub mod cbc;
|
||||
mod ec;
|
||||
pub mod ecdh;
|
||||
pub mod ecdsa;
|
||||
pub mod hmac;
|
||||
pub mod rng256;
|
||||
pub mod sha256;
|
||||
pub mod util;
|
||||
|
||||
// Trait for hash functions that returns a 256-bit hash.
|
||||
// The type must be Sized (size known at compile time) so that we can instanciate one on the stack
|
||||
// in the hash() method.
|
||||
pub trait Hash256: Sized {
|
||||
fn new() -> Self;
|
||||
fn update(&mut self, contents: &[u8]);
|
||||
fn finalize(self) -> [u8; 32];
|
||||
|
||||
fn hash(contents: &[u8]) -> [u8; 32] {
|
||||
let mut h = Self::new();
|
||||
h.update(contents);
|
||||
h.finalize()
|
||||
}
|
||||
}
|
||||
|
||||
// Traits for block ciphers that operate on 16-byte blocks.
|
||||
pub trait Encrypt16BytesBlock {
|
||||
fn encrypt_block(&self, block: &mut [u8; 16]);
|
||||
}
|
||||
|
||||
pub trait Decrypt16BytesBlock {
|
||||
fn decrypt_block(&self, block: &mut [u8; 16]);
|
||||
}
|
||||
|
||||
// Trait for hash functions that operate on 64-byte input blocks.
|
||||
pub trait HashBlockSize64Bytes {
|
||||
type State;
|
||||
|
||||
fn hash_block(state: &mut Self::State, block: &[u8; 64]);
|
||||
}
|
||||
91
libraries/crypto/src/rng256.rs
Normal file
91
libraries/crypto/src/rng256.rs
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use libtock::rng;
|
||||
|
||||
// Lightweight RNG trait to generate uniformly distributed 256 bits.
|
||||
pub trait Rng256 {
|
||||
fn gen_uniform_u8x32(&mut self) -> [u8; 32];
|
||||
|
||||
fn gen_uniform_u32x8(&mut self) -> [u32; 8] {
|
||||
bytes_to_u32(self.gen_uniform_u8x32())
|
||||
}
|
||||
}
|
||||
|
||||
// The TockOS rng driver fills a buffer of bytes, but we need 32-bit words for ECDSA.
|
||||
// This function does the conversion in safe Rust, using the native endianness to avoid unnecessary
|
||||
// instructions.
|
||||
// An unsafe one-line equivalent could be implemented with mem::transmute, but let's use safe Rust
|
||||
// when possible.
|
||||
fn bytes_to_u32(bytes: [u8; 32]) -> [u32; 8] {
|
||||
let mut result: [u32; 8] = [Default::default(); 8];
|
||||
for (i, r) in result.iter_mut().enumerate() {
|
||||
*r = u32::from_ne_bytes(*array_ref![bytes, 4 * i, 4]);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
// RNG backed by the TockOS rng driver.
|
||||
pub struct TockRng256 {}
|
||||
|
||||
impl Rng256 for TockRng256 {
|
||||
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
|
||||
let mut buf: [u8; 32] = [Default::default(); 32];
|
||||
rng::fill_buffer(&mut buf);
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
// For tests on the desktop, we use the cryptographically secure thread rng as entropy source.
|
||||
#[cfg(feature = "std")]
|
||||
pub struct ThreadRng256 {}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Rng256 for ThreadRng256 {
|
||||
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
|
||||
use rand::Rng;
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut result = [Default::default(); 32];
|
||||
rng.fill(&mut result);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_bytes_to_u32() {
|
||||
// This tests that all bytes of the input are indeed used in the output, once each.
|
||||
// Otherwise the result of gen_uniform_u32x8 wouldn't be uniformly distributed.
|
||||
let bytes = b"\x00\x01\x02\x03\x04\x05\x06\x07\
|
||||
\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\
|
||||
\x10\x11\x12\x13\x14\x15\x16\x17\
|
||||
\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f";
|
||||
#[cfg(target_endian = "big")]
|
||||
let expected = [
|
||||
0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f, 0x10111213, 0x14151617, 0x18191a1b,
|
||||
0x1c1d1e1f,
|
||||
];
|
||||
#[cfg(target_endian = "little")]
|
||||
let expected = [
|
||||
0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c, 0x13121110, 0x17161514, 0x1b1a1918,
|
||||
0x1f1e1d1c,
|
||||
];
|
||||
|
||||
assert_eq!(bytes_to_u32(*bytes), expected);
|
||||
}
|
||||
}
|
||||
423
libraries/crypto/src/sha256.rs
Normal file
423
libraries/crypto/src/sha256.rs
Normal file
@@ -0,0 +1,423 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::{Hash256, HashBlockSize64Bytes};
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use core::num::Wrapping;
|
||||
|
||||
const BLOCK_SIZE: usize = 64;
|
||||
|
||||
pub struct Sha256 {
|
||||
state: [Wrapping<u32>; 8],
|
||||
block: [u8; BLOCK_SIZE],
|
||||
total_len: usize,
|
||||
}
|
||||
|
||||
impl Hash256 for Sha256 {
|
||||
fn new() -> Self {
|
||||
Sha256 {
|
||||
state: Sha256::H,
|
||||
block: [0; BLOCK_SIZE],
|
||||
total_len: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, mut contents: &[u8]) {
|
||||
let cursor_in_block = self.total_len % BLOCK_SIZE;
|
||||
let left_in_block = BLOCK_SIZE - cursor_in_block;
|
||||
|
||||
// Increment the total length before we mutate the contents slice.
|
||||
self.total_len += contents.len();
|
||||
|
||||
if contents.len() < left_in_block {
|
||||
// The contents don't fill the current block. Simply copy the bytes.
|
||||
self.block[cursor_in_block..(cursor_in_block + contents.len())]
|
||||
.copy_from_slice(contents);
|
||||
} else {
|
||||
// First, fill and process the current block.
|
||||
let (this_block, rest) = contents.split_at(left_in_block);
|
||||
self.block[cursor_in_block..].copy_from_slice(this_block);
|
||||
Sha256::hash_block(&mut self.state, &self.block);
|
||||
contents = rest;
|
||||
|
||||
// Process full blocks.
|
||||
while contents.len() >= 64 {
|
||||
let (block, rest) = contents.split_at(64);
|
||||
Sha256::hash_block(&mut self.state, array_ref![block, 0, 64]);
|
||||
contents = rest;
|
||||
}
|
||||
|
||||
// Copy the last block for further processing.
|
||||
self.block[..contents.len()].copy_from_slice(contents);
|
||||
}
|
||||
}
|
||||
|
||||
fn finalize(mut self) -> [u8; 32] {
|
||||
// Last block and padding.
|
||||
let cursor_in_block = self.total_len % BLOCK_SIZE;
|
||||
self.block[cursor_in_block] = 0x80;
|
||||
// Clear the rest of the block.
|
||||
for byte in self.block[(cursor_in_block + 1)..].iter_mut() {
|
||||
*byte = 0;
|
||||
}
|
||||
|
||||
if cursor_in_block >= 56 {
|
||||
// Padding doesn't fit in this block, so we first hash this block and then hash a
|
||||
// padding block.
|
||||
Sha256::hash_block(&mut self.state, &self.block);
|
||||
// Clear buffer for the padding block.
|
||||
for byte in self.block.iter_mut() {
|
||||
*byte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// The last 8 bytes of the last block contain the length of the contents. It must be
|
||||
// expressed in bits, whereas `total_len` is in bytes.
|
||||
BigEndian::write_u64(array_mut_ref![self.block, 56, 8], self.total_len as u64 * 8);
|
||||
Sha256::hash_block(&mut self.state, &self.block);
|
||||
|
||||
// Encode the state's 32-bit words into bytes, using big-endian.
|
||||
let mut result: [u8; 32] = [0; 32];
|
||||
for i in 0..8 {
|
||||
BigEndian::write_u32(array_mut_ref![result, 4 * i, 4], self.state[i].0);
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl HashBlockSize64Bytes for Sha256 {
|
||||
type State = [Wrapping<u32>; 8];
|
||||
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
fn hash_block(state: &mut Self::State, block: &[u8; 64]) {
|
||||
let mut w: [Wrapping<u32>; 64] = [Wrapping(0); 64];
|
||||
|
||||
// Read the block as big-endian 32-bit words.
|
||||
for (i, item) in w.iter_mut().take(16).enumerate() {
|
||||
*item = Wrapping(BigEndian::read_u32(array_ref![block, 4 * i, 4]));
|
||||
}
|
||||
|
||||
for i in 16..64 {
|
||||
w[i] = w[i - 16] + Sha256::ssig0(w[i - 15]) + w[i - 7] + Sha256::ssig1(w[i - 2]);
|
||||
}
|
||||
|
||||
let mut a = state[0];
|
||||
let mut b = state[1];
|
||||
let mut c = state[2];
|
||||
let mut d = state[3];
|
||||
let mut e = state[4];
|
||||
let mut f = state[5];
|
||||
let mut g = state[6];
|
||||
let mut h = state[7];
|
||||
|
||||
for (i, item) in w.iter().enumerate() {
|
||||
let tmp1 =
|
||||
h + Sha256::bsig1(e) + Sha256::choice(e, f, g) + Wrapping(Sha256::K[i]) + *item;
|
||||
let tmp2 = Sha256::bsig0(a) + Sha256::majority(a, b, c);
|
||||
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + tmp1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = tmp1 + tmp2;
|
||||
}
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
state[5] += f;
|
||||
state[6] += g;
|
||||
state[7] += h;
|
||||
}
|
||||
}
|
||||
|
||||
impl Sha256 {
|
||||
// SHA-256 constants.
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
const H: [Wrapping<u32>; 8] = [
|
||||
Wrapping(0x6a09e667),
|
||||
Wrapping(0xbb67ae85),
|
||||
Wrapping(0x3c6ef372),
|
||||
Wrapping(0xa54ff53a),
|
||||
Wrapping(0x510e527f),
|
||||
Wrapping(0x9b05688c),
|
||||
Wrapping(0x1f83d9ab),
|
||||
Wrapping(0x5be0cd19),
|
||||
];
|
||||
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
const K: [u32; 64] = [
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
|
||||
0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
|
||||
0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
|
||||
0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
|
||||
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
|
||||
0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
|
||||
0xc67178f2,
|
||||
];
|
||||
|
||||
// SHA-256 helper functions.
|
||||
#[inline(always)]
|
||||
fn choice(e: Wrapping<u32>, f: Wrapping<u32>, g: Wrapping<u32>) -> Wrapping<u32> {
|
||||
(e & f) ^ (!e & g)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn majority(a: Wrapping<u32>, b: Wrapping<u32>, c: Wrapping<u32>) -> Wrapping<u32> {
|
||||
(a & b) ^ (a & c) ^ (b & c)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn bsig0(x: Wrapping<u32>) -> Wrapping<u32> {
|
||||
x.rotate_right(2) ^ x.rotate_right(13) ^ x.rotate_right(22)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn bsig1(x: Wrapping<u32>) -> Wrapping<u32> {
|
||||
x.rotate_right(6) ^ x.rotate_right(11) ^ x.rotate_right(25)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ssig0(x: Wrapping<u32>) -> Wrapping<u32> {
|
||||
x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ssig1(x: Wrapping<u32>) -> Wrapping<u32> {
|
||||
x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
extern crate hex;
|
||||
|
||||
#[test]
|
||||
fn test_choice() {
|
||||
assert_eq!(
|
||||
Sha256::choice(
|
||||
Wrapping(0b00001111),
|
||||
Wrapping(0b00110011),
|
||||
Wrapping(0b01010101)
|
||||
),
|
||||
Wrapping(0b01010011)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_majority() {
|
||||
assert_eq!(
|
||||
Sha256::majority(
|
||||
Wrapping(0b00001111),
|
||||
Wrapping(0b00110011),
|
||||
Wrapping(0b01010101)
|
||||
),
|
||||
Wrapping(0b00010111)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash_empty() {
|
||||
assert_eq!(
|
||||
Sha256::hash(&[]),
|
||||
hex::decode("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
|
||||
.unwrap()
|
||||
.as_slice()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_for_various_splits() {
|
||||
// Test vector generated with the following Python script:
|
||||
//
|
||||
// import hashlib
|
||||
// print(hashlib.sha256('A' * 512).hexdigest())
|
||||
//
|
||||
let input = vec![b'A'; 512];
|
||||
let hash = hex::decode("32beecb58a128af8248504600bd203dcc676adf41045300485655e6b8780a01d")
|
||||
.unwrap();
|
||||
|
||||
for i in 0..512 {
|
||||
for j in i..512 {
|
||||
let mut h = Sha256::new();
|
||||
h.update(&input[..i]);
|
||||
h.update(&input[i..j]);
|
||||
h.update(&input[j..]);
|
||||
assert_eq!(h.finalize(), hash.as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash_for_various_lengths() {
|
||||
// This test makes sure that the padding is implemented properly.
|
||||
//
|
||||
// Test vectors generated with the following Python script:
|
||||
//
|
||||
// import hashlib
|
||||
// for n in range(128):
|
||||
// print('b"' + hashlib.sha256('A' * n).hexdigest() + '",')
|
||||
//
|
||||
let hashes: [&[u8; 64]; 128] = [
|
||||
b"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
b"559aead08264d5795d3909718cdd05abd49572e84fe55590eef31a88a08fdffd",
|
||||
b"58bb119c35513a451d24dc20ef0e9031ec85b35bfc919d263e7e5d9868909cb5",
|
||||
b"cb1ad2119d8fafb69566510ee712661f9f14b83385006ef92aec47f523a38358",
|
||||
b"63c1dd951ffedf6f7fd968ad4efa39b8ed584f162f46e715114ee184f8de9201",
|
||||
b"11770b3ea657fe68cba19675143e4715c8de9d763d3c21a85af6b7513d43997d",
|
||||
b"69dc6c3210e25e62c5938ff4e841e81ce3c7d2cde583553478a77d7fcb389f30",
|
||||
b"0f0cf9286f065a2f38e3c4e4886578e35af4050c108e507998a05888c98667ea",
|
||||
b"c34ab6abb7b2bb595bc25c3b388c872fd1d575819a8f55cc689510285e212385",
|
||||
b"e5f9176ecd90317cf2d4673926c9db65475b0b58e7f468586ddaef280a98cdbd",
|
||||
b"1d65bf29403e4fb1767522a107c827b8884d16640cf0e3b18c4c1dd107e0d49d",
|
||||
b"dd20088919031875b7bcca29995545dd40ca994be0558183f9b942b51b3b2249",
|
||||
b"0592cedeabbf836d8d1c7456417c7653ac208f71e904d3d0ab37faf711021aff",
|
||||
b"3461164897596e65b79bc0b7bee8cc7685487e37f52ecf0b34c000329675b859",
|
||||
b"14f99c4b0a6493e3a3f52022cd75276b4cff9a7c8eef74793267f687b600af96",
|
||||
b"6f9f84c09a5950e1ea7888f17922a69e5292dcbcb1e682ddfc977a9b4ea1a8c0",
|
||||
b"991204fba2b6216d476282d375ab88d20e6108d109aecded97ef424ddd114706",
|
||||
b"444074d5328d52b4e0036d37b1b6ea0a9fe3b0c96872d1157fbf01b6fdb2ce8d",
|
||||
b"d273c6b6de3f5260e123348e0feb270126fa06e164bb82818df7c71b30ab0ef5",
|
||||
b"234b7f9389f9b521f407805760775940d79a48188338d02a1fe654e826a83f69",
|
||||
b"edfcaac579024f574adbcaa3c13e4fd2b7f1797826afe679f2144af2cb5c062d",
|
||||
b"f48de1653fdfa9b637b7fb4da9c169a1f2be6a1ec001e3d2cca44c669a693ecf",
|
||||
b"8a5bdb4cc15164126c6ef2668de9dd240d299ce6397a42c95a9411b93d080ed8",
|
||||
b"1786ac1492c6c922c2734e4d3d8e9b030cfba291a72bc135989c49fc31171ac2",
|
||||
b"1bda9f0aed80857d43c9329457f28b1ca29f736a0c539901e1ba16a909eb07b4",
|
||||
b"6724431fc312ba42c98b38b8595a49749419526aa89722c77a85c6c813dfdb5a",
|
||||
b"06f469c97c14e84c74853bb96aa79305eb4f6635291bf1202c4fdadb82706204",
|
||||
b"568f214d529544bf4430513c2993495a5b434611533c63d1cf095b51c5e1f8af",
|
||||
b"c84f7630cbe823fc4d80f605b98294592f15b14db1f78d6f18e686c1f8cb5ded",
|
||||
b"a7951e0ca2e9612a985a36747309822a67a9b8c1a5abd848c03e82216c85f1b3",
|
||||
b"37b9403cf88cc2639d0a118d757a43a0ff6d4871823707ab6a8bb56bc68e8e79",
|
||||
b"55ee740f58335c97d42c32125218eb7c325fbe34206912f1aa7af7fd6580c9a1",
|
||||
b"22a48051594c1949deed7040850c1f0f8764537f5191be56732d16a54c1d8153",
|
||||
b"5d873590851b7b00b60490c8e6966b3409c385adcc9590d801f0e03e268b5ba5",
|
||||
b"1e98a405718c430a4067d75125015a947a971449bc433b078418438c48bc6046",
|
||||
b"015c50632207f69408c05d20e36facfad9bde74c727f933023f54cd6e8b87372",
|
||||
b"a3b99d59dbb025726312e812c2821cfbe55189f515414bdabd5e3d284c8ad6f9",
|
||||
b"7d24c321bfb2a5b6d2c7a3c2948855cef421d08352dc296ed95c6f645fcce441",
|
||||
b"876fc5bf6bde065afea543aceb645ce17ffe3c9d8df9c6073ab31f3a562f4257",
|
||||
b"b9b515854e040b8de31d85d597aba28db4467fd0a7d6eb77a31005f4a67a8fb3",
|
||||
b"f0a2fb80ac0699075fb6c7b0ee2bcc204a1d909ee3149571216ec9cc1d4b9f8e",
|
||||
b"b78244167af116f2b3597b4a81421bd2b28f3d8bf616025a5ae424f689fd7632",
|
||||
b"d85ce644bf4e82cee032eaa5c3d9030a090276d9bae3703112bdfc6f8fdde307",
|
||||
b"0f007385b6f9d4b7eeb2748605afe1a984a0a3bfa3f014d09e2a784ce9e5cd1a",
|
||||
b"b06b3f20c246db70a136e3ae4787d0df96db4f693d215c21883d3c19700fb276",
|
||||
b"ac752ced452069c55c7567a0717b87615824c568dc98c8626ac85fc34b234c3b",
|
||||
b"91a07088de2d0fe9f31567b05d290e65feb06758d000ec463f7f5a6e82ce00a5",
|
||||
b"abf6c5d1b6512e188f1da6a72e974f7b98b5bac62453f1748c8f9ab180803fdb",
|
||||
b"4739dcdbab0c377161c539af55d47c5c90c87807d0728aabe91697b66e29096c",
|
||||
b"ff85f0693c8e6bbeeaa1f90c32e1159b9b545d830ffe58cd80cb94d9d8140d21",
|
||||
b"509ddb85fdf92f197d32570c005cdcb6dffa398f088bd1a013459f6fb1f730ef",
|
||||
b"1d31616e307323bd80775ae7483fce654a3b65bced7134c22e179a2e25155009",
|
||||
b"3e1ae21112ec8fad05e3676e1940da52d56771162142aac4d73743e7df70b686",
|
||||
b"5f2671f97427c8873e5af72686d244e4c8126a4f618983bae880a48a834a0607",
|
||||
b"2d0009d7df28cdc6b5a4c36063d97415a8fe99515317458fcb0b0e2a821dbcb9",
|
||||
b"8963cc0afd622cc7574ac2011f93a3059b3d65548a77542a1559e3d202e6ab00",
|
||||
b"6ea719cefa4b31862035a7fa606b7cc3602f46231117d135cc7119b3c1412314",
|
||||
b"a00df74fbdadd9eb0e7742a019e5b2d77374de5417eba5b7a0730a60cce5e7bf",
|
||||
b"cee244d999f8cf49f2a4ee4d89695130c9c95c33538cedf0306881ebd42714d2",
|
||||
b"5b29354ee33cba5b924ded5e3c873a76e1d12527d824ace01ff9683d24e06816",
|
||||
b"c5fb235befd875b915fa6c4702a7abb93cacf3d7c414b71cbeff9e1b0a9fbd41",
|
||||
b"0ae45129ef1edf64309559f6cb7bb0af16eff14ad82f24d55fa029c1b4144078",
|
||||
b"5a2aafcacb9828e41fb7c8f8098952638645874b3a8ca45d2523fb2d5fc7166d",
|
||||
b"1b58d00f5b1fbd2a1884d666a2be33c2fa7463dff32cd60ef200c0f750a6b70f",
|
||||
b"d53eda7a637c99cc7fb566d96e9fa109bf15c478410a3f5eb4d4c4e26cd081f6",
|
||||
b"836203944f4c0280461ad73d31457c22ba19d1d99e232dc231000085899e00a2",
|
||||
b"fd8afe9151793a84a21af054ba985d1486a705561e2a50d4a50f814664f5e806",
|
||||
b"f495547fca5a5a2c40dccebefe40160efb8bc2888e8afef712b096b5f2585b44",
|
||||
b"ba31b89f9486439fdf551f597fede0c10260f9b404866dba4a6555375f486359",
|
||||
b"46f23cc7ccba8af67978bea568e63cd045be72aba974132b1b14cc59277329f1",
|
||||
b"01d3a187638cc1a7740a74fbeb57aa2648dbdec42d497321912bf393d283ccd1",
|
||||
b"96b437b3df7c62fc877a121b087899f5e36a58f6d87ba52d997e92bb016aa575",
|
||||
b"6a6d691ac9ba70955046757cd685b6257773ff3ad93f43d4d4812c5b106f4b5b",
|
||||
b"beb869adc22a7e8fbd5af12cbf3ad36dd92dca6ebf52ef3441ed6cd0dff24dc6",
|
||||
b"0f40cb2f3661d73dfaec511e8ebea082fb1f77db45bf8c9ba7c9708da6ba6301",
|
||||
b"ddd5d1ecc7af6a5b0d18e0825004d3bc9d52e2cdf14bc00c7474f16941a64acc",
|
||||
b"6a10b9a8a33d7814ce73679ace5c43657aa6d63169ce215fd85177c77a94147d",
|
||||
b"9d887d47c78267827dac4afb2cbdcc593d1b89c1d0c1f22c3800cae7916962cd",
|
||||
b"e45ca598e970afb0f1f57bd34e87065839d2fac524421048fbec489f68e1fd0d",
|
||||
b"1581baebc5f9dcfd89c658b3c3303203fc0e2f93e3f9e0b593d8b2b8112c6eda",
|
||||
b"d9b1f3e2c6d528668a73f22575c44ed9f98d9c684964761b621417efd80d7a60",
|
||||
b"9feacd760dfda20e5e0accf9ddeb8b5c01276a56dc3518046a26f5276fe15041",
|
||||
b"6aacf5279e24979684fab16fb5495c3ac1dfcf7138b0825376af83473d07cae9",
|
||||
b"cd2f0deb953014ee400eddef094602d9676e0fd2269d22818f0d5bc198d44d8d",
|
||||
b"ff9265df14681e44d170fd2b10c6cdf3991f731601d6b89cafe39691d3b42559",
|
||||
b"6c99e32b005a3a4956b9406ab15411e666c7f67982db170ae1fb111ec634b9c4",
|
||||
b"e1659ad54063a379f77fee108a376a6a7d5ae3d0c437bf847203963bd0078dfc",
|
||||
b"572d07a66fccf05d5f73c913552e12d9ffb39a15d01a8fd48cd6aaaab86f4f14",
|
||||
b"ca97d312ef8551820844548f300f9528f27d53f6ad3910ed2709f2b35c9591f3",
|
||||
b"97654dc78f4f7d4cec4b4870e6ee0a87abacc89337ed0629e2e511e4466df56d",
|
||||
b"fde923c1ed5e5cd32c629bdf341db32c0f72ba8f1e2afd9c194e87e0e3d9da5f",
|
||||
b"d6624a66f3bcc4adef8a17abf9eeb1fbf23746165b2f90f9cb3a679a58e4958e",
|
||||
b"8676909e9578a790f84be31fe94f4d22488f912b754ee816ba0a5c4a392305a5",
|
||||
b"57f65fd8a95ff738b95dba0f1606025535e34591f1b58b00d33958093808360c",
|
||||
b"f6afcaf794fe0e04d6ec18bbde55412a60c0c5ef55e75223b817e97f208bbccc",
|
||||
b"6121f27b52c1f17ddce365143ba58a720fa303707faa32a4e5e89029f34ac618",
|
||||
b"69d62c062d67d8d2ce9068c1898fb9746c911839aa88ad1628d090f4c8e47f05",
|
||||
b"eb9f8b69313e19e14b1043b3cac05d18d40321536ad485be8145007aefa9295d",
|
||||
b"b1cfb0f511886ca07ade919740ca95e1b3d998ba7cb66ba2badd53be28f5f509",
|
||||
b"d0118863549f990558685da9090ca8eae8c809c5545c4aa85f8e5eec413b2555",
|
||||
b"d82c6aa133a0fc25b087f46ad7ed2a3042772e612e015571e61753ff55ba6da8",
|
||||
b"aac76dab773c00c8ad4bb128147945c70798eae5a2511fef01e853c6e3051ab9",
|
||||
b"ccd77d7adb6178ee3e3560ba4583044a36b296257ae4c5cfead96d46af31fccd",
|
||||
b"3c4f48a886b2de7e908d6a626074e7515265cc9d1188c161cf159fd376d3d5f8",
|
||||
b"7f9578a31905e95a16cc9d3e7b57dc3158a23dccf359a1f2cf09e73eb13e5cde",
|
||||
b"770492ebaee89a20d19f9972c3e3d0c7d51c9baaedf06fdfe9a7b69da3394779",
|
||||
b"893785aaddea396621c31dc5d465e2775cbc6b7423dc3498e80aa5da7a6a819d",
|
||||
b"1b2b69fbec485ef3f347ee6dc9c87d73505e45b5c9b02599b823ac94f5d642a1",
|
||||
b"724b4b3d3e8ac7588561ca00eec11693f6b85c03bb6b1302d458a7a4ce4b39e4",
|
||||
b"6a30ef4094128b6fa463b70cb21d141da92711d80ea94c9b73fb8a0471cc49a9",
|
||||
b"50968cf735e3f6a47834ae3745816234f72fd156aef1bec4b6a7d3a3151773bc",
|
||||
b"3ed01dd816dc93ea2d445681df11aa24e9fd1441de429eb0ee7816ccc09a2b7a",
|
||||
b"64bdc48c731313c7b37c1f1d13d6265ac7a2604ff630b50f591a86e610cb3005",
|
||||
b"96666c386cf99a74ec9eb55a5545aa90a3e53a8bbbe74cd3334b32d4968a3214",
|
||||
b"33555a41335654a29d5b7799bf180915e09095d21991dacf071583957b9e3f35",
|
||||
b"ffd391d554ce0672ae818a149dd55325f4cb933c97017b8148934474355d5a88",
|
||||
b"cf2050114ccaefd8a0ea6cf31d85e0232eadc8fd61277ff16496d2234b55c7d7",
|
||||
b"e42142b4243d5a2c59a2977d0385d49eab288085f8d38ead3ae5d87145c562ec",
|
||||
b"3bb810492422cc5c7466d86dcd8095b0d87e97634656a3fa5fe2270a2244c16b",
|
||||
b"17d2f0f7197a6612e311d141781f2b9539c4aef7affd729246c401890e000dde",
|
||||
b"a4f4256159ea6fb23b27eb8c5eb9cfb9083475985f355a85c78de8f2fef2b3ac",
|
||||
b"a36c4cf85204c67047c00d5dcc16677978839af0f0fde7ff973c98b66e244552",
|
||||
b"4a596559f450ce5e3a777d952d8d2ed8611e9f3facc8400483371f6eadc4bdb2",
|
||||
b"64855e54c94d14ab53afc6109d3c0033c665fab85b57c0e7d4e8da55b3b26952",
|
||||
b"a2ee2228d4798988ce3ac273c0cd8b9bbc4e3e58413eb22dfbe6395758659a2b",
|
||||
b"35c28ee2e25f5ad70384f1ca9723f520c955fb5fe9f2e56b9dc809479a9ca8cc",
|
||||
b"da3f6a7f55f821760330dd14495e68e7d153b05e472d38459d4728d63ad9df26",
|
||||
b"026134f6117e45a37c5c2dc2f330bdd274c6dc087526b91ecec4d6dac9bb7346",
|
||||
];
|
||||
|
||||
let mut input = Vec::new();
|
||||
for i in 0..128 {
|
||||
assert_eq!(
|
||||
Sha256::hash(&input),
|
||||
hex::decode(hashes[i] as &[u8]).unwrap().as_slice()
|
||||
);
|
||||
input.push(b'A');
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: more tests
|
||||
}
|
||||
41
libraries/crypto/src/util.rs
Normal file
41
libraries/crypto/src/util.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#[cfg(test)]
|
||||
use subtle::CtOption;
|
||||
|
||||
pub type Block16 = [u8; 16];
|
||||
|
||||
#[inline(always)]
|
||||
pub fn xor_block_16(block: &mut Block16, mask: &Block16) {
|
||||
for i in 0..16 {
|
||||
block[i] ^= mask[i];
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub trait ToOption<T> {
|
||||
fn to_option(self) -> Option<T>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<T> ToOption<T> for CtOption<T> {
|
||||
fn to_option(self) -> Option<T> {
|
||||
if bool::from(self.is_some()) {
|
||||
Some(self.unwrap())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user