From 7b30164ad62219186bf1325f4db21aa2c1f294db Mon Sep 17 00:00:00 2001 From: Moudy Date: Tue, 12 Aug 2025 04:23:00 +0200 Subject: [PATCH] Adding Shake256 --- shake256-demo/.DS_Store | Bin 6148 -> 6148 bytes shake256-demo/Cargo.toml | 5 ++ shake256-demo/methods/.DS_Store | Bin 0 -> 6148 bytes shake256-demo/methods/Cargo.toml | 10 +++ shake256-demo/methods/build.rs | 3 + shake256-demo/methods/guest/.DS_Store | Bin 0 -> 6148 bytes shake256-demo/methods/guest/Cargo.toml | 15 ++++ shake256-demo/methods/guest/src/lib.rs | 2 + shake256-demo/methods/guest/src/main.rs | 95 +++++++++++++++++++++++ shake256-demo/methods/src/main.rs | 83 ++++++++++++++++++++ shake256-demo/src/lib.rs | 99 ++++++++++++++++++------ shake256-demo/src/main.rs | 80 ++++++++++++------- 12 files changed, 343 insertions(+), 49 deletions(-) create mode 100644 shake256-demo/methods/.DS_Store create mode 100644 shake256-demo/methods/Cargo.toml create mode 100644 shake256-demo/methods/build.rs create mode 100644 shake256-demo/methods/guest/.DS_Store create mode 100644 shake256-demo/methods/guest/Cargo.toml create mode 100644 shake256-demo/methods/guest/src/lib.rs create mode 100644 shake256-demo/methods/guest/src/main.rs create mode 100644 shake256-demo/methods/src/main.rs diff --git a/shake256-demo/.DS_Store b/shake256-demo/.DS_Store index 0e33cd1e1b7712ffd1920d24eb4e099dbcd6b5a3..a9fbadef0d16f59d1102d74fc74aea166e680768 100644 GIT binary patch delta 76 zcmZoMXfc@J&&a(oU^g=(_hcTHsr>8=xeTccB@7u1`3xxx#gpAwPe`MQl?4~&<>cq3 TGcYhPZl1?d!nB#4<1aq|^AQvf delta 31 ncmZoMXfc@J&&atkU^g=(=VTt1shg*<7BWq2__~>$<1aq|q+SZ> diff --git a/shake256-demo/Cargo.toml b/shake256-demo/Cargo.toml index 126afe9..a1c369a 100644 --- a/shake256-demo/Cargo.toml +++ b/shake256-demo/Cargo.toml @@ -12,10 +12,15 @@ serde = { version = "1.0", features = ["derive"] } sha2 = "0.10" hkdf = "0.12" sha3 = "0.10" +serde-big-array = "0.5" [dev-dependencies] rand = "0.8" cipher = { version = "0.4", features = ["std"] } +serde = { version = "1", default-features = false, features = ["derive", "alloc"] } + + + [build-dependencies] risc0-build = "2.3.1" diff --git a/shake256-demo/methods/.DS_Store b/shake256-demo/methods/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4ffb5e9e2372918c9e8840c5f96ca3975356462a GIT binary patch literal 6148 zcmeHK&2AGh5FRHf-Lyi=0VH}rT7*jnW10I@+J+5JlPp zH_DqJapnnl1D=FCjO__*et;XTDvvb&yq+2Vd=uL-0I*&WIsh#Iuuvs7cCgqW(k^vP zYSbcwnd&2ieMljD!o_gS+cX#k3 z?(;DS-0wM-F>tx(D>0u}Vz$t`fDvSnuXw&i&-azyE1tnLn^2!$f(ehZywmx{YW2p} zm2GR=+O=MLCt~X5eqLlfKYb~`o(aK&McogcN2BSWb?sOrxgRB?R0Txg2wh&ih>}oD zd!k6fOvQTIU^T7gptU!f9o~P?w(mNQGjH3o?m?$*ce@AkdDFUn``*K+gLgbm#0NzQ zFgyU2TqRt<8CEJw;$z1fig>axFI!{L@6&><$HA?$=AEyS{7QT*!hd*7PX0E+sh1{P zBxCGV&bW>VNnyC05_S`fdzF-s*JViuEoVb2$Wl#1?fa*Xl!jl{-ziwPZlIsyR;Wkz z&spdvYwe!%Jk0Qh0mHz>V?dq{HmXFIu+*rI4lL9Y0I`A1O0X{fGRPR4&?PK2q6LNN zP(&Td=!wB}IJVp5=Mt70bvQ73d@vfB(F=vC(XoG9xdU@Gn$j>}7+7YYu0LDy{(to6 z_y2N``7#U`1}+r?tkL)SJzNsqt!s;ucdd>3233mmD>bSREa*B`6?qlkKvjY^TUHQV V!crr)pqM`biUv~{2L3ApKLOh0>GS{q literal 0 HcmV?d00001 diff --git a/shake256-demo/methods/Cargo.toml b/shake256-demo/methods/Cargo.toml new file mode 100644 index 0000000..9ab59da --- /dev/null +++ b/shake256-demo/methods/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "methods" +version = "0.1.0" +edition = "2021" + +[build-dependencies] +risc0-build = { version = "2.3.1" } + +[package.metadata.risc0] +methods = ["methods/guest"] diff --git a/shake256-demo/methods/build.rs b/shake256-demo/methods/build.rs new file mode 100644 index 0000000..08a8a4e --- /dev/null +++ b/shake256-demo/methods/build.rs @@ -0,0 +1,3 @@ +fn main() { + risc0_build::embed_methods(); +} diff --git a/shake256-demo/methods/guest/.DS_Store b/shake256-demo/methods/guest/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..72caf1de9d8fbfb306b1aa0a10d198b7323540be GIT binary patch literal 6148 zcmeHK!EO^V5FIBe-L$Hd1E^e(EOCuWS`ZL%*{0>dl|}T>R$(`Z%BtISmEDj-6lt&U zGaUI7eh1#zPNgK}+E!>r8b5nHZ!JGt_L_)PZ!+8`Y7tQYXRI|*++y6%zGgKa*#Ij0 z4MTgBk)Z)yu4PN$Au7OYw?#)3)0i%>ayRSuAv1#{GYR^6a~#6={#Zk8l~aOwMcE4H z=L)Az1x6VxXQ^kmXC>3(+K>M$xz5s}>~wysTD`IHXfxOhwuAHNtC>b+TuzE!JU->t zCu6c?QIC_)>1f(-Jw7sd8K?PZYzgUbgp{+BG#{F2&rI@RVY!j(2%15&-`btcUcG+V z)^Fa<+j`bL=(KgWdoZ6jgD1~ly!+U{%&v0topr#@$JV#D<8c8$Q1Mg#7LD`F^&=&^EWj}8>}2>@&$Yz=k(U1W~- z7<#N6q6elN73iqSKQWY}Bd&d3=&^F>=%oDPL-~=Ff1xNlI=-)MI;qg1l%jwru&hAc zHCufDzyJ69f0-mLQ9u;, + pub ipk_bytes: Vec, + pub commitment: [u8; 32], + pub out_index: u32, + pub pt: Vec, +} + + +#[derive(Debug, Serialize, Deserialize)] +pub struct EncInput { + pub plaintext: Vec, + pub ss_bytes: [u8; 32], + pub epk_bytes: Vec, + pub ipk_bytes: Vec, + pub commitment: [u8; 32], + pub out_index: u32, +} + +fn nssa_kdf( + ss_bytes: &[u8; 32], + epk: &[u8], + ipk: &[u8], + commitment: &[u8; 32], + out_index: u32, +) -> ([u8; 32], Vec) { + // salt = SHA256("NSSA/v0.1/KDF-SHA256") + let mut hasher = Sha256::new(); + sha2::Digest::update(&mut hasher, b"NSSA/v0.1/KDF-SHA256"); + let salt = hasher.finalize(); + + let hk = Hkdf::::new(Some(&salt), ss_bytes); + + // info = "NSSA/v0.1/enc" || Epk || Ipk || commitment || le(out_index) + let mut info = Vec::with_capacity(3 + 33 + 33 + 32 + 4 + 16); + info.extend_from_slice(b"NSSA/v0.1/enc"); + info.extend_from_slice(epk); + info.extend_from_slice(ipk); + info.extend_from_slice(commitment); + info.extend_from_slice(&out_index.to_le_bytes()); + + let mut k_enc = [0u8; 32]; + hk.expand(&info, &mut k_enc).unwrap(); + + (k_enc, info) +} + +fn enc_xor_shake256(k_enc: &[u8; 32], ad: &[u8], pt: &[u8]) -> Vec { + let mut shake = Shake256::default(); + shake.update(b"NSSA/v0.1/ENC/SHAKE256"); + shake.update(k_enc); + shake.update(ad); + let mut xof = shake.finalize_xof(); + + let mut ks = vec![0u8; pt.len()]; + xof.read(&mut ks); + + pt.iter().zip(ks).map(|(p, k)| p ^ k).collect() +} + +pub fn main() { + let input: EncInput = env::read(); + + let (k_enc, info) = nssa_kdf( + &input.ss_bytes, + &input.epk_bytes, + &input.ipk_bytes, + &input.commitment, + input.out_index, + ); + + let ct = enc_xor_shake256(&k_enc, &info, &input.plaintext); + + // Commit ciphertext to the journal + env::commit_slice(&ct); +} diff --git a/shake256-demo/methods/src/main.rs b/shake256-demo/methods/src/main.rs new file mode 100644 index 0000000..71b3587 --- /dev/null +++ b/shake256-demo/methods/src/main.rs @@ -0,0 +1,83 @@ +#![no_std] +#![no_main] + +extern crate alloc; + +use alloc::vec::Vec; +use hkdf::Hkdf; +use risc0_zkvm::guest::env; +use risc0_zkvm::guest::entry; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use sha3::{digest::{ExtendableOutput, Update, XofReader}, Shake256}; + +entry!(main); + + +#[derive(Debug, Serialize, Deserialize)] +pub struct EncInput { + pub plaintext: Vec, + pub ss_bytes: [u8; 32], + pub epk_bytes: Vec, + pub ipk_bytes: Vec, + pub commitment: [u8; 32], + pub out_index: u32, +} + +fn nssa_kdf( + ss_bytes: &[u8; 32], + epk: &[u8; 32], + ipk: &[u8; 32], + commitment: &[u8; 32], + out_index: u32, +) -> ([u8; 32], Vec) { + // salt = SHA256("NSSA/v0.1/KDF-SHA256") + let mut hasher = Sha256::new(); + hasher.update(b"NSSA/v0.1/KDF-SHA256"); + let salt = hasher.finalize(); + + let hk = Hkdf::::new(Some(&salt), ss_bytes); + + // info = "NSSA/v0.1/enc" || Epk || Ipk || commitment || le(out_index) + let mut info = Vec::with_capacity(3 + 33 + 33 + 32 + 4 + 16); + info.extend_from_slice(b"NSSA/v0.1/enc"); + info.extend_from_slice(epk); + info.extend_from_slice(ipk); + info.extend_from_slice(commitment); + info.extend_from_slice(&out_index.to_le_bytes()); + + let mut k_enc = [0u8; 32]; + hk.expand(&info, &mut k_enc).unwrap(); + + (k_enc, info) +} + +fn enc_xor_shake256(k_enc: &[u8; 32], ad: &[u8], pt: &[u8]) -> Vec { + let mut shake = Shake256::default(); + shake.update(b"NSSA/v0.1/ENC/SHAKE256"); + shake.update(k_enc); + shake.update(ad); + let mut xof = shake.finalize_xof(); + + let mut ks = vec![0u8; pt.len()]; + xof.read(&mut ks); + + pt.iter().zip(ks).map(|(p, k)| p ^ k).collect() +} + +pub fn main() { + let input: EncInput = env::read(); + + let (k_enc, info) = nssa_kdf( + &input.ss_bytes, + &input.epk_compressed, + &input.ipk_compressed, + &input.commitment, + input.out_index, + ); + + let ct = enc_xor_shake256(&k_enc, &info, &input.plaintext); + + // Commit ciphertext to the journal + env::commit_slice(&ct); +} diff --git a/shake256-demo/src/lib.rs b/shake256-demo/src/lib.rs index d2461e1..c333117 100644 --- a/shake256-demo/src/lib.rs +++ b/shake256-demo/src/lib.rs @@ -1,37 +1,92 @@ #[cfg(not(rust_analyzer))] -mod generated { +pub mod methods { include!(concat!(env!("OUT_DIR"), "/methods.rs")); } -#[cfg(not(rust_analyzer))] -pub use generated::{GUEST_ELF, GUEST_ID}; +#[cfg(not(rust_analyzer))] #[cfg(rust_analyzer)] pub const GUEST_ELF: &[u8] = &[]; #[cfg(rust_analyzer)] pub const GUEST_ID: [u32; 8] = [0; 8]; -use anyhow::Result; -use risc0_zkvm::{default_prover, ExecutorEnv, Receipt}; -pub fn prove_encrypt( - key: [u8; 32], - nonce: [u8; 12], - plaintext: &[u8], -) -> Result<(Receipt, Vec)> { - let env = ExecutorEnv::builder() - .write(&key)? - .write(&nonce)? - .write(&plaintext.to_vec())? - .build()?; +use hkdf::Hkdf; +use sha2::{Digest as Sha2Digest, Sha256}; +use sha3::{Shake256, digest::{Update, ExtendableOutput, XofReader}}; +use serde::{Deserialize, Serialize}; +//use serde_big_array::BigArray; - let prover = default_prover(); - let prove_info = prover.prove(env, GUEST_ELF)?; - let receipt = prove_info.receipt; - receipt.verify(GUEST_ID)?; - let ciphertext: Vec = receipt.journal.bytes.clone(); // if this errors, use .to_vec() - - Ok((receipt, ciphertext)) +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct KeystreamRequest { + pub kdf_salt: [u8; 32], + pub ss_bytes: [u8; 32], + pub epk_bytes: Vec, + pub ipk_bytes: Vec, + pub commitment: [u8; 32], + pub out_index: u32, + pub pt: Vec, +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct KdfInputs { + pub epk_bytes: Vec, + pub ipk_bytes: Vec, + pub commitment: [u8; 32], + pub out_index: u32, +} + +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)] +pub struct EncInput { + pub plaintext: Vec, + pub ss_bytes: [u8; 32], // ECDH x-coordinate (sender view) + pub epk_bytes: Vec, + pub ipk_bytes: Vec, + pub commitment: [u8; 32], + pub out_index: u32, +} + +/// KDF per NSSA spec: HKDF-SHA256 with fixed salt and domain-separated info. +pub fn nssa_kdf( + ss_bytes: &[u8; 32], + epk: &[u8], + ipk: &[u8], + commitment: &[u8; 32], + out_index: u32, +) -> ([u8; 32], Vec) { + // salt = SHA256("NSSA/v0.1/KDF-SHA256") + let mut hasher = Sha256::new(); + Sha2Digest::update(&mut hasher, b"NSSA/v0.1/KDF-SHA256"); // avoids E0034 + let salt = hasher.finalize(); + + let hk = Hkdf::::new(Some(&salt), ss_bytes); + + // info = "NSSA/v0.1/enc" || Epk || Ipk || commitment || le(out_index) + let mut info = Vec::with_capacity(3 + 33 + 33 + 32 + 4 + 16); + info.extend_from_slice(b"NSSA/v0.1/enc"); + info.extend_from_slice(epk); + info.extend_from_slice(ipk); + info.extend_from_slice(commitment); + info.extend_from_slice(&out_index.to_le_bytes()); + + let mut k_enc = [0u8; 32]; + hk.expand(&info, &mut k_enc) + .expect("HKDF-Expand must produce 32 bytes"); + + (k_enc, info) +} + +/// SHAKE256-XOF keystream XOR (symmetric). +pub fn enc_xor_shake256(k_enc: &[u8; 32], ad: &[u8], pt: &[u8]) -> Vec { + let mut shake = Shake256::default(); + shake.update(b"NSSA/v0.1/ENC/SHAKE256"); // domain sep + shake.update(k_enc); + shake.update(ad); + let mut xof = shake.finalize_xof(); + + let mut ks = vec![0u8; pt.len()]; + xof.read(&mut ks); + + pt.iter().zip(ks).map(|(p, k)| p ^ k).collect() } diff --git a/shake256-demo/src/main.rs b/shake256-demo/src/main.rs index 61db16b..c67611c 100644 --- a/shake256-demo/src/main.rs +++ b/shake256-demo/src/main.rs @@ -1,44 +1,70 @@ #[cfg(not(rust_analyzer))] -include!(concat!(env!("OUT_DIR"), "/methods.rs")); #[cfg(rust_analyzer)] -mod methods { - pub const GUEST_ELF: &[u8] = &[]; - pub const GUEST_ID: [u32; 8] = [0; 8]; -} +//mod methods { + // pub const GUEST_ELF: &[u8] = &[]; + // pub const GUEST_ID: [u32; 8] = [0; 8]; +//} #[cfg(rust_analyzer)] use methods::*; use anyhow::Result; -use hex::encode; use risc0_zkvm::{default_prover, ExecutorEnv}; +use shake256_demo::{enc_xor_shake256, nssa_kdf, EncInput}; +//ßuse methods::GUEST_ELF; + +use serde::{Serialize, Deserialize}; +//use serde_big_array::BigArray; +use hex::ToHex; // for encode_hex +use shake256_demo::methods::GUEST_ELF; // <— crate name uses underscore + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct KeystreamRequest { + pub kdf_salt: [u8; 32], + pub ss_bytes: [u8; 32], + pub epk_bytes: Vec, + pub ipk_bytes: Vec, + pub commitment: [u8; 32], + pub out_index: u32, + pub pt: Vec, +} + fn main() -> Result<()> { - // Example inputs - let key = [0x42u8; 32]; - let nonce = [0x24u8; 12]; - let plaintext = b"Hello, RISC Zero ChaCha20 demo!"; + // Tiny demo inputs (in real NSSA you’d compute ss via ECDH). + let plaintext = b"hello NSSA (shake256)".to_vec(); + let ss_bytes = [1u8; 32]; + let epk = vec![2u8; 33]; + let ipk = vec![3u8; 33]; + let commitment = [4u8; 32]; + let out_index = 0u32; - let env = ExecutorEnv::builder() - .write(&key)? - .write(&nonce)? - .write(&plaintext.to_vec())? - .build()?; - - - let prover = default_prover(); - let prove_info = prover.prove(env, GUEST_ELF)?; - let receipt = prove_info.receipt; - - // (Optionally) verify the proof - receipt.verify(GUEST_ID)?; + let input = EncInput { + plaintext: plaintext.clone(), + ss_bytes, + epk_bytes: epk.clone(), + ipk_bytes: ipk.clone(), + commitment, + out_index, + }; - // Extract and print the ciphertext - let ct: &[u8] = &receipt.journal.bytes; - println!("Ciphertext: {}", encode(ct)); + // Prove inside zkVM + let env = ExecutorEnv::builder().write(&input)?.build()?; + let prove_info = default_prover().prove(env, GUEST_ELF)?; + println!("WARNING: proving in dev mode. Not production-safe."); + // Ciphertext from journal + let guest_ct = prove_info.receipt.journal.bytes.to_vec(); + println!("guest ct: {}", guest_ct.encode_hex::()); + + // Host recompute (sanity) + let (k_enc, info) = nssa_kdf(&ss_bytes, &epk, &ipk, &commitment, out_index); + let host_ct = enc_xor_shake256(&k_enc, &info, &plaintext); + println!("host ct: {}", host_ct.encode_hex::()); + + assert_eq!(guest_ct, host_ct); + println!("OK: guest and host ciphertexts match."); Ok(()) } -