-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
out-of-circuit encryption and decryption
- Loading branch information
1 parent
7cbe9a0
commit 59f9f33
Showing
2 changed files
with
159 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
use starknet_crypto::{poseidon_hash_many, poseidon_hash_single}; | ||
use starknet_types_core::{ | ||
curve::{AffinePoint, ProjectivePoint}, | ||
felt::Felt, | ||
}; | ||
|
||
// The PLAINTEXT_NUM should be fixed to achieve the indistinguishability of resource logics | ||
// Make it 10 | ||
pub const PLAINTEXT_NUM: usize = 10; | ||
pub const CIPHERTEXT_NUM: usize = PLAINTEXT_NUM + 2; | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct Ciphertext([Felt; CIPHERTEXT_NUM]); | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct Plaintext([Felt; PLAINTEXT_NUM]); | ||
|
||
// Symmetric encryption key | ||
#[derive(Debug, Clone)] | ||
pub struct SecretKey(AffinePoint); | ||
|
||
impl Ciphertext { | ||
pub fn inner(&self) -> &[Felt; CIPHERTEXT_NUM] { | ||
&self.0 | ||
} | ||
|
||
pub fn encrypt(message: &Plaintext, secret_key: &SecretKey, encrypt_nonce: &Felt) -> Self { | ||
// Init poseidon state | ||
let (secret_key_x, secret_key_y) = secret_key.get_coordinates(); | ||
let mut poseidon_state = poseidon_hash_many(&vec![ | ||
secret_key_x, | ||
secret_key_y, | ||
*encrypt_nonce, | ||
Felt::from(PLAINTEXT_NUM), | ||
]); | ||
|
||
// Encrypt | ||
let mut cipher = vec![]; | ||
message.inner().iter().for_each(|f| { | ||
poseidon_state += f; | ||
cipher.push(poseidon_state); | ||
poseidon_state = poseidon_hash_single(poseidon_state); | ||
}); | ||
|
||
// Add encrypt_nonce | ||
cipher.push(*encrypt_nonce); | ||
|
||
// Add MAC | ||
cipher.push(poseidon_state); | ||
cipher.into() | ||
} | ||
|
||
pub fn decrypt(&self, secret_key: &SecretKey) -> Option<Vec<Felt>> { | ||
let cipher_text = self.inner(); | ||
let cipher_len = cipher_text.len(); | ||
let mac = cipher_text[cipher_len - 1]; | ||
let encrypt_nonce = cipher_text[cipher_len - 2]; | ||
let (secret_key_x, secret_key_y) = secret_key.get_coordinates(); | ||
// Init poseidon sponge state | ||
let mut poseidon_state = poseidon_hash_many(&vec![ | ||
secret_key_x, | ||
secret_key_y, | ||
encrypt_nonce, | ||
Felt::from(cipher_len - 2), | ||
]); | ||
|
||
// Decrypt | ||
let mut msg = vec![]; | ||
for cipher_element in &cipher_text[0..cipher_len - 2] { | ||
let msg_element = *cipher_element - poseidon_state; | ||
msg.push(msg_element); | ||
poseidon_state = *cipher_element; | ||
poseidon_state = poseidon_hash_single(poseidon_state); | ||
} | ||
|
||
if mac != poseidon_state { | ||
return None; | ||
} | ||
|
||
Some(msg) | ||
} | ||
} | ||
|
||
impl From<Vec<Felt>> for Ciphertext { | ||
fn from(input_vec: Vec<Felt>) -> Self { | ||
Ciphertext( | ||
input_vec | ||
.try_into() | ||
.expect("public input with incorrect length"), | ||
) | ||
} | ||
} | ||
|
||
impl Plaintext { | ||
pub fn inner(&self) -> &[Felt; PLAINTEXT_NUM] { | ||
&self.0 | ||
} | ||
|
||
pub fn to_vec(&self) -> Vec<Felt> { | ||
self.0.to_vec() | ||
} | ||
|
||
pub fn padding(msg: &[Felt]) -> Self { | ||
let mut plaintext = msg.to_owned(); | ||
let padding = std::iter::repeat(Felt::ZERO).take(PLAINTEXT_NUM - msg.len()); | ||
plaintext.extend(padding); | ||
plaintext.into() | ||
} | ||
} | ||
|
||
impl From<Vec<Felt>> for Plaintext { | ||
fn from(input_vec: Vec<Felt>) -> Self { | ||
Plaintext( | ||
input_vec | ||
.try_into() | ||
.expect("public input with incorrect length"), | ||
) | ||
} | ||
} | ||
|
||
impl SecretKey { | ||
pub fn from_dh_exchange(pk: AffinePoint, sk: Felt) -> Self { | ||
Self( | ||
(&ProjectivePoint::try_from(pk).unwrap() * sk) | ||
.to_affine() | ||
.unwrap(), | ||
) | ||
} | ||
|
||
pub fn get_coordinates(&self) -> (Felt, Felt) { | ||
(self.0.x(), self.0.y()) | ||
} | ||
} | ||
|
||
#[test] | ||
fn test_encryption() { | ||
use rand::{thread_rng, RngCore}; | ||
use starknet_curve::curve_params::GENERATOR; | ||
|
||
// Key generation | ||
let mut rng = thread_rng(); | ||
let mut felt: [u8; 32] = Default::default(); | ||
rng.fill_bytes(&mut felt); | ||
let random_sk = Felt::from_bytes_be_slice(&felt); | ||
let pk = GENERATOR; | ||
|
||
let key = SecretKey::from_dh_exchange(pk, random_sk); | ||
let message = [Felt::ONE, Felt::ZERO, Felt::ONE]; | ||
let plaintext = Plaintext::padding(message.as_ref()); | ||
let encrypt_nonce = Felt::from(23333u128); | ||
|
||
// Encryption | ||
let cipher = Ciphertext::encrypt(&plaintext, &key, &encrypt_nonce); | ||
|
||
// Decryption | ||
let decryption = cipher.decrypt(&key).unwrap(); | ||
assert_eq!(plaintext.to_vec(), decryption); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
mod compliance_input; | ||
mod encryption; | ||
mod errors; | ||
mod utils; | ||
|
||
|