arnaucube
arnaucube/plonky2-crypto-gadgetsPublic Self-hosted repository
plonky2-crypto-gadgets/poseidon-cipher/src/lib.rs
poseidon-cipher/src/lib.rsRaw
  1//! For LICENSE check out https://github.com/0xPARC/plonky2-aes/blob/main/LICENSE
  2#![allow(incomplete_features)]
  3#![feature(generic_const_exprs)]
  4#![allow(dead_code)] // TMP
  5#![allow(non_snake_case)]
  6
  7use num::bigint::BigUint;
  8use num_bigint::RandBigInt;
  9use plonky2::{
 10    field::{
 11        extension::{quintic::QuinticExtension, FieldExtension},
 12        goldilocks_field::GoldilocksField as F,
 13        types::{Field, Field64},
 14    },
 15    hash::{hashing::hash_n_to_hash_no_pad, poseidon::PoseidonPermutation},
 16};
 17use pod2::backends::plonky2::primitives::ec::curve::{Point, GROUP_ORDER};
 18use rand::{rngs::OsRng, Rng};
 19
 20// ECField
 21type Fq = QuinticExtension<F>;
 22
 23pub fn new_key() -> (BigUint, Point) {
 24    let k: BigUint = OsRng.gen_biguint_below(&GROUP_ORDER);
 25    // let k: Fq = QuinticExtension(std::array::from_fn(|_| {
 26    //     F::from_canonical_u64(OsRng.gen_range(0..F::ORDER))
 27    // }));
 28    // let k = F::from_canonical_u64(OsRng.gen_range(0..F::ORDER));
 29    let K = &k * Point::generator();
 30    (k, K)
 31}
 32pub fn expanded_key(K: Point) -> Point {
 33    let r: BigUint = OsRng.gen_biguint_below(&GROUP_ORDER);
 34    // let r: Fq = QuinticExtension(std::array::from_fn(|_| {
 35    //     F::from_canonical_u64(OsRng.gen_range(0..F::ORDER))
 36    // }));
 37    &r * K // TODO maybe separate into x, u (ECField)
 38}
 39
 40pub fn encrypt(ks: Point, msg: Vec<Fq>, nonce: F) -> Vec<Fq> {
 41    // pad m
 42    dbg!(&msg.len());
 43    let mut m = msg.clone();
 44    m.resize(m.len().next_multiple_of(3), Fq::ZERO);
 45    dbg!(&m.len());
 46
 47    let l = Fq::from(F::from_canonical_u64(msg.len() as u64));
 48    let n = Fq::from(nonce);
 49    // WIP TODO
 50    let two32 = Fq::from(F::from_canonical_u64(2_u64.pow(32)));
 51    let two64: Fq = two32 * two32;
 52    let two128: Fq = two64 * two64;
 53    let nl128: Fq = n + l * two128; // TODO
 54    let mut s: [Fq; 4] = [Fq::ZERO, ks.x, ks.u, nl128];
 55
 56    let mut ct: Vec<Fq> = vec![];
 57    for i in 0..m.len() / 3 {
 58        s = hash_state(s);
 59
 60        // absorb
 61        s[1] = s[1] + m[i * 3];
 62        s[2] = s[2] + m[i * 3 + 1];
 63        s[3] = s[3] + m[i * 3 + 2];
 64
 65        // release
 66        ct.push(s[1]);
 67        ct.push(s[2]);
 68        ct.push(s[3]);
 69    }
 70    s = hash_state(s);
 71    ct.push(s[1]);
 72    ct
 73}
 74
 75pub fn decrypt(ks: Point, ct: Vec<Fq>, nonce: F, l: usize) -> Vec<Fq> {
 76    let l_fq = Fq::from(F::from_canonical_u64(l as u64));
 77    let n = Fq::from(nonce);
 78    // WIP TODO
 79    let two32 = Fq::from(F::from_canonical_u64(2_u64.pow(32)));
 80    dbg!(2_u64.pow(32));
 81    dbg!(F::from_canonical_u64(2_u64.pow(32)));
 82    dbg!(&two32);
 83    let two64: Fq = two32 * two32;
 84    dbg!(&two64);
 85    let two128: Fq = two64 * two64;
 86    dbg!(&two128);
 87    let nl128: Fq = n + l_fq * two128; // TODO
 88    let mut s: [Fq; 4] = [Fq::ZERO, ks.x, ks.u, nl128];
 89
 90    // let mut m: Vec<Fq> = vec![Fq::ZERO; ct.len() / 3];
 91    let mut m: Vec<Fq> = vec![];
 92    for i in 0..ct.len() / 3 {
 93        s = hash_state(s);
 94
 95        // release
 96        // m[3 * i] = s[1] + ct[3 * i];
 97        // m[3 * i + 1] = s[2] + ct[3 * i + 1];
 98        // m[3 * i + 2] = s[3] + ct[3 * i + 2];
 99        m.push(s[1] + ct[3 * i]);
100        m.push(s[2] + ct[3 * i + 1]);
101        m.push(s[3] + ct[3 * i + 2]);
102
103        // modify state
104        s[1] = ct[3 * i];
105        s[2] = ct[3 * i + 1];
106        s[3] = ct[3 * i + 2];
107    }
108
109    if l > 3 {
110        if l % 3 == 2 {
111            assert_eq!(m[m.len() - 1], Fq::ZERO);
112        } else if l % 3 == 1 {
113            assert_eq!(m[m.len() - 1], Fq::ZERO);
114            assert_eq!(m[m.len() - 2], Fq::ZERO);
115        }
116    }
117    s = hash_state(s);
118    assert_eq!(ct[ct.len() - 1], s[1]);
119    m[0..l].to_vec()
120}
121
122fn hash_state(s: [Fq; 4]) -> [Fq; 4] {
123    let elems: Vec<F> = s
124        .iter()
125        .map(|e| {
126            {
127                let aux: [F; 5] = e.to_basefield_array();
128                aux
129            }
130            .to_vec()
131        })
132        .collect::<Vec<Vec<F>>>()
133        .concat();
134    let h = hash_n_to_hash_no_pad::<F, PoseidonPermutation<_>>(&elems).elements;
135    let mut h5: [F; 5] = [F::ZERO; 5];
136    h5[..4].copy_from_slice(&h);
137    [Fq::from_basefield_array(h5), Fq::ZERO, Fq::ZERO, Fq::ZERO]
138}
139
140#[cfg(test)]
141mod tests {
142    use plonky2::field::types::Sample;
143
144    // use rand::prelude::*;
145    use super::*;
146
147    #[test]
148    fn test_encrypt_decrypt() {
149        test_encrypt_decrypt_op(9);
150        test_encrypt_decrypt_op(10);
151        test_encrypt_decrypt_op(11);
152        test_encrypt_decrypt_op(12);
153        test_encrypt_decrypt_op(128);
154        test_encrypt_decrypt_op(129);
155    }
156    fn test_encrypt_decrypt_op(msg_len: usize) {
157        let mut rng = rand::thread_rng();
158
159        let (_k, K) = new_key();
160        let ks = expanded_key(K);
161        let nonce = F::rand();
162        let msg: Vec<Fq> = (0..msg_len).map(|_| Fq::sample(&mut rng)).collect();
163        let l = msg.len();
164
165        let ct = encrypt(ks, msg.clone(), nonce);
166
167        let m = decrypt(ks, ct, nonce, l);
168        assert_eq!(m, msg);
169    }
170}