core_crypto/
block_cipher.rs

1// Copyright 2021 BlockPuppets developers.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use anyhow::Result;
10use curve25519::edwards::CompressedEdwardsY;
11use curve25519::scalar::Scalar;
12use sha3::Digest;
13
14use super::{PrivateKey, PublicKey, SharedSecret, H256, KEY_BYTES_SIZE};
15
16/// This trait defines an association of symbol or nis1 encrypt and decrypt message.
17///
18pub trait BlockCipher: Sized {
19    fn encrypt_message(
20        signer_sk: &[u8; KEY_BYTES_SIZE],
21        receiver_pk: &[u8; KEY_BYTES_SIZE],
22        msg: &[u8],
23    ) -> Result<Vec<u8>>;
24
25    fn decrypt_message(
26        receiver_sk: &[u8; KEY_BYTES_SIZE],
27        signer_pk: &[u8; KEY_BYTES_SIZE],
28        enc_msg: &[u8],
29    ) -> Result<Vec<u8>>;
30}
31
32// internal functions.
33pub fn derive_shared_secret<D: Digest>(
34    secret_key: PrivateKey,
35    public_key: PublicKey,
36) -> SharedSecret {
37    let public = CompressedEdwardsY::from_slice(public_key.as_ref())
38        .decompress()
39        .unwrap();
40
41    let secret = scalar_from_sk::<D>(secret_key);
42
43    let shared_point = secret * &(public);
44    let shared_point_compressed = shared_point.compress();
45    SharedSecret::from(shared_point_compressed.as_bytes())
46}
47
48// internal functions.
49fn scalar_from_sk<D: Digest>(secret_key: PrivateKey) -> Scalar {
50    let sk_hash = D::digest(secret_key.as_bytes());
51
52    let mut sk_hash_fix: H256 = H256::default();
53    sk_hash_fix.assign_from_slice(&sk_hash.as_slice()[0..32]);
54
55    sk_hash_fix.0[0] &= 0xF8; // The lowest three bits must be 0
56    sk_hash_fix.0[31] &= 0x7F; // The highest bit must be 0
57    sk_hash_fix.0[31] |= 0x40; // The second highest bit must be 1
58
59    Scalar::from_bits(sk_hash_fix.into())
60}