Skip to content

Commit

Permalink
out-of-circuit encryption and decryption
Browse files Browse the repository at this point in the history
  • Loading branch information
XuyangSong committed Oct 16, 2024
1 parent 7cbe9a0 commit 59f9f33
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 0 deletions.
158 changes: 158 additions & 0 deletions native/cairo_prover/src/encryption.rs
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);
}
1 change: 1 addition & 0 deletions native/cairo_prover/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod compliance_input;
mod encryption;
mod errors;
mod utils;

Expand Down

0 comments on commit 59f9f33

Please sign in to comment.