From 9ae6e7df64ee828a1bbed87492da5d386663893c Mon Sep 17 00:00:00 2001 From: pdtfh <149602456+pdtfh@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:02:25 +0100 Subject: [PATCH] proof context / external nullifier generation --- Cargo.lock | 1 + walletkit-core/Cargo.toml | 1 + walletkit-core/src/identity.rs | 4 +- walletkit-core/src/proof.rs | 100 +++++++++++++++++++++++++++++++-- walletkit-core/src/u256.rs | 2 +- 5 files changed, 99 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a20bb4a1..5857ced3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5087,6 +5087,7 @@ dependencies = [ name = "walletkit-core" version = "0.0.6" dependencies = [ + "alloy-core", "hex", "ruint", "semaphore", diff --git a/walletkit-core/Cargo.toml b/walletkit-core/Cargo.toml index ac40014d..6e104b0a 100644 --- a/walletkit-core/Cargo.toml +++ b/walletkit-core/Cargo.toml @@ -15,6 +15,7 @@ crate-type = ["lib", "staticlib", "cdylib"] name = "walletkit_core" [dependencies] +alloy-core = { version = "0.8.12", default-features = false, features = ["sol-types"] } hex = "0.4.3" ruint = { version = "1.12.3", default-features = false, features = ["alloc"] } semaphore = { git = "https://github.com/worldcoin/semaphore-rs", rev = "accb14b", features = ["depth_30"] } diff --git a/walletkit-core/src/identity.rs b/walletkit-core/src/identity.rs index 3a58f1bc..f7baaca6 100644 --- a/walletkit-core/src/identity.rs +++ b/walletkit-core/src/identity.rs @@ -28,7 +28,7 @@ impl Identity { /// [Protocol Reference](https://docs.semaphore.pse.dev/V2/technical-reference/circuits#nullifier-hash). #[must_use] pub fn generate_nullifier_hash(&self, context: &Context) -> U256Wrapper { - generate_nullifier_hash(&self.0, context.external_nullifier).into() + generate_nullifier_hash(&self.0, context.external_nullifier.into()).into() } } @@ -39,7 +39,7 @@ mod tests { #[test] fn test() { let identity = Identity::new(b"not_a_real_secret"); - let context = Context::new(b"app_id", b"action"); + let context = Context::new(b"app_id", None); let nullifier_hash = identity.generate_nullifier_hash(&context); println!("{}", nullifier_hash.to_hex_string()); } diff --git a/walletkit-core/src/proof.rs b/walletkit-core/src/proof.rs index a123fe06..33422aef 100644 --- a/walletkit-core/src/proof.rs +++ b/walletkit-core/src/proof.rs @@ -1,19 +1,107 @@ -use ruint::aliases::U256; +use alloy_core::sol_types::SolValue; use semaphore::hash_to_field; +use crate::u256::U256Wrapper; + #[derive(Clone, PartialEq, Eq, Debug, uniffi::Object)] pub struct Context { - pub external_nullifier: U256, + pub external_nullifier: U256Wrapper, } #[uniffi::export] impl Context { #[must_use] #[uniffi::constructor] - pub fn new(app_id: &[u8], action: &[u8]) -> Self { - let external_nullifier = hash_to_field(app_id); - dbg!(&action); - // TODO: handle action properly + pub fn new(app_id: &[u8], action: Option>) -> Self { + let mut pre_image = hash_to_field(app_id).abi_encode_packed(); + + if let Some(action) = action { + pre_image.extend_from_slice(&action); + } + + let external_nullifier = hash_to_field(&pre_image).into(); + Self { external_nullifier } } } + +#[cfg(test)] +mod tests { + use alloy_core::primitives::address; + use ruint::{aliases::U256, uint}; + + use super::*; + + #[test] + fn test_external_nullifier_hash_generation_no_action() { + let context = Context::new(b"app_369183bd38f1641b6964ab51d7a20434", None); + assert_eq!( + context.external_nullifier.to_hex_string(), + "0x0073e4a6b670e81dc619b1f8703aa7491dc5aaadf75409aba0ac2414014c0227" + ); + + let context = Context::new(b"app_369183bd38f1641b6964ab51d7a20434", Some(b"".to_vec())); + assert_eq!( + context.external_nullifier.to_hex_string(), + "0x0073e4a6b670e81dc619b1f8703aa7491dc5aaadf75409aba0ac2414014c0227" + ); + } + + /// This test case comes from the real example in the docs. + /// Reference: + #[test] + fn test_external_nullifier_hash_generation_string_action_staging() { + let context = Context::new( + b"app_staging_45068dca85829d2fd90e2dd6f0bff997", + Some(b"test-action-qli8g".to_vec()), + ); + assert_eq!( + context.external_nullifier.to_hex_string(), + "0x00d8b157e767dc59faa533120ed0ce34fc51a71937292ea8baed6ee6f4fda866" + ); + } + + #[test] + fn test_external_nullifier_hash_generation_string_action() { + let context = Context::new(b"app_10eb12bd96d8f7202892ff25f094c803", Some(b"test-123123".to_vec())); + assert_eq!( + context.external_nullifier.0, + // cspell:disable-next-line + uint!(0x0065ebab05692ff2e0816cc4c3b83216c33eaa4d906c6495add6323fe0e2dc89_U256) + ); + } + + #[test] + fn test_external_nullifier_hash_generation_with_complex_abi_encoded_values() { + let custom_action = [ + address!("541f3cc5772a64f2ba0a47e83236CcE2F089b188").abi_encode_packed(), + U256::from(1).abi_encode_packed(), + "hello".abi_encode_packed(), + ] + .concat(); + + let context = Context::new(b"app_10eb12bd96d8f7202892ff25f094c803", Some(custom_action)); + assert_eq!( + context.external_nullifier.to_hex_string(), + // expected output obtained from Solidity + "0x00f974ff06219e8ca992073d8bbe05084f81250dbd8f37cae733f24fcc0c5ffd" + ); + } + + #[test] + fn test_external_nullifier_hash_generation_with_complex_abi_encoded_values_staging() { + let custom_action = [ + "world".abi_encode_packed(), + U256::from(1).abi_encode_packed(), + "hello".abi_encode_packed(), + ] + .concat(); + + let context = Context::new(b"app_staging_45068dca85829d2fd90e2dd6f0bff997", Some(custom_action)); + assert_eq!( + context.external_nullifier.to_hex_string(), + // expected output obtained from Solidity + "0x005b49f95e822c7c37f4f043421689b11f880e617faa5cd0391803bc9bcc63c0" + ); + } +} diff --git a/walletkit-core/src/u256.rs b/walletkit-core/src/u256.rs index 0198544a..024cb418 100644 --- a/walletkit-core/src/u256.rs +++ b/walletkit-core/src/u256.rs @@ -9,7 +9,7 @@ use ruint::aliases::U256; /// Particularly, when sending proof inputs/outputs as JSON on HTTP requests, the values SHOULD /// be represented as padded hex strings from Big Endian bytes. #[allow(clippy::module_name_repetitions)] -#[derive(uniffi::Object, Debug, PartialEq, Eq, Clone)] +#[derive(uniffi::Object, Debug, PartialEq, Eq, Clone, Copy)] pub struct U256Wrapper(pub U256); #[uniffi::export]