arnaucube
arnaucube/plonky2-crypto-gadgetsPublic Self-hosted repository
extend nonce from F to [F;2] (<2^128)
arnaucube git@arnaucube.com
Mon, 23 Feb 2026 16:40:36 +0000
commit

d41afd78cdbab1d94311c914bee25da53303af86

parent

67245856314890e671a4aba674e8af9af1bd2281

3 files changed, 25 insertions(+), 18 deletions(-)

jump to
M poseidon-cipher/Cargo.toml → poseidon-cipher/Cargo.toml

@@ -4,10 +4,8 @@ version = "0.1.0"

edition = "2024" [dependencies] -plonky2 = { git = "https://github.com/0xPARC/plonky2.git", rev = "109d517d09c210ae4c2cee381d3e3fbc04aa3812" } -anyhow = "1.0.56" -# plonky2 = { workspace = true } -# anyhow = { workspace = true } +plonky2 = { workspace = true } +anyhow = { workspace = true } num = { version = "0.4.3", features = ["num-bigint"] } pod2 = { git = "https://github.com/0xPARC/pod2", rev = "cdf227e3530247e07e375daed007cae7d443b4ae" } # for ecgfp5 num-bigint = { version = "0.4.6", features = ["rand"] }
M poseidon-cipher/src/circuit.rs → poseidon-cipher/src/circuit.rs

@@ -1,4 +1,7 @@

//! For LICENSE check out https://github.com/0xPARC/plonky2-crypto-gadgets/blob/main/LICENSE +//! +//! Implements the Plonky2 circuits for Poseidon encryption as described at +//! https://drive.google.com/file/d/1EVrP3DzoGbmzkRmYnyEDcIQcXVU7GlOd/view . use std::array;

@@ -7,7 +10,7 @@ use plonky2::{

field::{ extension::{FieldExtension, quintic::QuinticExtension}, goldilocks_field::GoldilocksField as F, - types::Field, + types::{Field, Field64}, }, hash::poseidon::PoseidonHash, iop::{

@@ -35,7 +38,7 @@ [(); L + 1]:,

{ ks: PointTarget, m: [FqT; L], - nonce: Target, + nonce: [Target; 2], ct: [FqT; L + 1], }

@@ -45,17 +48,18 @@ [(); L + 1]:,

{ pub fn build(builder: &mut CircuitBuilder<F, D>) -> Self { assert!(L.is_multiple_of(3)); + assert!(L < F::ORDER as usize); let fqt_zero = const_fqt_zero(builder); // add targets let ks: PointTarget = builder.add_virtual_point_target(); let m: [FqT; L] = array::from_fn(|_| builder.add_virtual_nnf_target()); - let nonce: Target = builder.add_virtual_target(); + let nonce: [Target; 2] = builder.add_virtual_target_arr::<2>(); let mut ct: [FqT; L + 1] = array::from_fn(|_| fqt_zero.clone()); // build the circuit logic let f_zero = builder.constant(F::ZERO); - let n = FqT::new([nonce, f_zero, f_zero, f_zero, f_zero]); + let n = FqT::new([nonce[0], nonce[1], f_zero, f_zero, f_zero]); let two128: Fq = two_128(); let l_two128: Fq = Fq::from_basefield_array([ F::from_canonical_u64(L as u64),

@@ -93,7 +97,7 @@ &self,

pw: &mut PartialWitness<F>, ks: Point, m: &[Fq], - nonce: F, + nonce: [F; 2], ct: &[Fq], ) -> Result<()> { assert_eq!(m.len(), L);

@@ -106,7 +110,7 @@ for j in 0..5 {

pw.set_target(self.m[i].components[j], m[i].0[j])?; } } - pw.set_target(self.nonce, nonce)?; + pw.set_target_arr(&self.nonce, &nonce)?; #[allow(clippy::needless_range_loop)] for i in 0..L + 1 { for j in 0..5 {

@@ -159,7 +163,7 @@ const L: usize = 129; // (multiple of 3)

let (_k, K) = crate::new_key(); let ks = crate::expanded_key(K); - let nonce = F::rand(); + let nonce: [F; 2] = [F::rand(), F::rand()]; let msg: Vec<Fq> = (0..L).map(|_| Fq::sample(&mut rng)).collect(); let l = msg.len();
M poseidon-cipher/src/lib.rs → poseidon-cipher/src/lib.rs

@@ -1,4 +1,7 @@

//! For LICENSE check out https://github.com/0xPARC/plonky2-crypto-gadgets/blob/main/LICENSE +//! +//! Implements Poseidon encryption as described at +//! https://drive.google.com/file/d/1EVrP3DzoGbmzkRmYnyEDcIQcXVU7GlOd/view . #![allow(incomplete_features)] #![feature(generic_const_exprs)]

@@ -48,13 +51,13 @@ // dbg!(&two128);

two128 } -pub fn encrypt(ks: Point, msg: &[Fq], nonce: F) -> Vec<Fq> { - // pad m - let mut m = msg.to_vec(); +pub fn encrypt(ks: Point, msg: &[Fq], nonce: [F; 2]) -> Vec<Fq> { + let mut m = msg.to_vec(); // pad m m.resize(m.len().next_multiple_of(3), Fq::ZERO); let l = Fq::from(F::from_canonical_u64(msg.len() as u64)); - let n = Fq::from(nonce); + let nonce_5: [F; 5] = [nonce[0], nonce[1], F::ZERO, F::ZERO, F::ZERO]; + let n = Fq::from_basefield_array(nonce_5); let nl128: Fq = n + l * two_128(); let mut s: [Fq; 4] = [Fq::ZERO, ks.x, ks.u, nl128];

@@ -77,9 +80,10 @@ ct[m.len()] = s[1];

ct } -pub fn decrypt(ks: Point, ct: &[Fq], nonce: F, l: usize) -> Vec<Fq> { +pub fn decrypt(ks: Point, ct: &[Fq], nonce: [F; 2], l: usize) -> Vec<Fq> { let l_fq = Fq::from(F::from_canonical_u64(l as u64)); - let n = Fq::from(nonce); + let nonce_5: [F; 5] = [nonce[0], nonce[1], F::ZERO, F::ZERO, F::ZERO]; + let n = Fq::from_basefield_array(nonce_5); let nl128: Fq = n + l_fq * two_128(); let mut s: [Fq; 4] = [Fq::ZERO, ks.x, ks.u, nl128];

@@ -113,6 +117,7 @@ }

fn hash_state(s: [Fq; 4]) -> [Fq; 4] { let elems: [F; 4 * 5] = array::from_fn(|i| s[i / 5].0[i % 5]); + // Note: here we're using plonky2's normal poseidon, not duplex-sponge let h = hash_n_to_m_no_pad::<F, PoseidonPermutation<_>>(&elems, 4 * 5); array::from_fn(|i| Fq::from_basefield_array(array::from_fn::<_, 5, _>(|j| h[j + 5 * i]))) }

@@ -140,7 +145,7 @@ let mut rng = rand::thread_rng();

let (_k, K) = new_key(); let ks = expanded_key(K); - let nonce = F::rand(); + let nonce: [F; 2] = [F::rand(), F::rand()]; let msg: Vec<Fq> = (0..msg_len).map(|_| Fq::sample(&mut rng)).collect(); let l = msg.len();