Skip to content

Commit

Permalink
Nullifier hash generation & U256Wrapper (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
pdtfh authored Nov 21, 2024
1 parent 970fbb5 commit 30bf785
Show file tree
Hide file tree
Showing 9 changed files with 5,854 additions and 328 deletions.
6,001 changes: 5,679 additions & 322 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"ignorePaths": ["Cargo.toml"],
"words": [
"aarch",
"ruint",
"Uniffi",
"WalletKit",
"Worldcoin",
Expand Down
5 changes: 5 additions & 0 deletions walletkit-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,9 @@ crate-type = ["lib", "staticlib", "cdylib"]
name = "walletkit_core"

[dependencies]
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"] }
serde_json = "1.0.133"
thiserror = "2.0.3"
uniffi = { workspace = true, features = ["build"] }
8 changes: 8 additions & 0 deletions walletkit-core/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use thiserror::Error;

#[derive(Debug, Error, uniffi::Error)]
#[uniffi(flat_error)]
pub enum Error {
#[error("fetching_inclusion_proof_failed")]
FetchingInclusionProofFailed,
}
46 changes: 46 additions & 0 deletions walletkit-core/src/identity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use semaphore::protocol::generate_nullifier_hash;

use crate::{proof::Context, u256::U256Wrapper};

#[derive(Clone, PartialEq, Eq, Debug, uniffi::Object)]
pub struct Identity(pub semaphore::identity::Identity);

impl From<Identity> for semaphore::identity::Identity {
fn from(identity: Identity) -> Self {
identity.0
}
}

#[uniffi::export]
impl Identity {
#[must_use]
#[uniffi::constructor]
pub fn new(secret: &[u8]) -> Self {
let mut secret_key = secret.to_vec();
let identity = semaphore::identity::Identity::from_secret(&mut secret_key, None);
Self(identity)
}

/// Generates a nullifier hash for a particular context (i.e. app + action) and the identity.
/// The nullifier hash is a unique pseudo-random number for the particular identity and context.
/// More information can be found [here](https://docs.world.org/world-id/concepts#vocabulary)
///
/// [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()
}
}

#[cfg(test)]
mod tests {

use super::*;
#[test]
fn test() {
let identity = Identity::new(b"not_a_real_secret");
let context = Context::new(b"app_id", b"action");
let nullifier_hash = identity.generate_nullifier_hash(&context);
println!("{}", nullifier_hash.to_hex_string());
}
}
7 changes: 5 additions & 2 deletions walletkit-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#![deny(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
#![deny(clippy::all, clippy::pedantic, clippy::nursery)]

pub mod math;
pub mod error;
pub mod identity;
pub mod proof;
pub mod u256;

uniffi::setup_scaffolding!("walletkit_core");
4 changes: 0 additions & 4 deletions walletkit-core/src/math.rs

This file was deleted.

22 changes: 22 additions & 0 deletions walletkit-core/src/proof.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use semaphore::hash_to_field;

use crate::u256::U256Wrapper;

#[derive(Clone, PartialEq, Eq, Debug, uniffi::Object)]
pub struct Context {
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
Self {
external_nullifier: external_nullifier.into(),
}
}
}
88 changes: 88 additions & 0 deletions walletkit-core/src/u256.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use std::ops::Deref;

use ruint::aliases::U256;

/// A wrapper around `U256` to represent a field element in the protocol. Wrapper enables FFI interoperability.
///
/// Most inputs and outputs from the zero-knowledge proofs are `U256` values.
/// While using `U256` directly is convenient and recommended when working with the proofs, particularly in Rust,
/// it is not a user-friendly type for interactions or communications in other languages / systems.
///
/// 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)]
pub struct U256Wrapper(pub U256);

#[uniffi::export]
impl U256Wrapper {
#[must_use]
pub fn to_hex_string(&self) -> String {
format!("0x{}", hex::encode(self.0.to_be_bytes::<32>()))
}
}

impl From<U256Wrapper> for U256 {
fn from(val: U256Wrapper) -> Self {
val.0
}
}

impl From<U256> for U256Wrapper {
fn from(val: U256) -> Self {
Self(val)
}
}

impl std::fmt::Display for U256Wrapper {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_hex_string())
}
}

impl Deref for U256Wrapper {
type Target = U256;

fn deref(&self) -> &Self::Target {
&self.0
}
}

#[cfg(test)]
mod tests {
use super::*;
use ruint::uint;

#[test]
fn test_to_hex_string_for_u256() {
assert_eq!(
U256Wrapper(U256::from(1)).to_hex_string(),
"0x0000000000000000000000000000000000000000000000000000000000000001"
);
assert_eq!(
U256Wrapper(U256::from(42)).to_hex_string(),
"0x000000000000000000000000000000000000000000000000000000000000002a"
);

assert_eq!(
U256Wrapper(uint!(999999_U256)).to_hex_string(),
"0x00000000000000000000000000000000000000000000000000000000000f423f"
);

assert_eq!(
U256Wrapper(uint!(
80084422859880547211683076133703299733277748156566366325829078699459944778998_U256
))
.to_hex_string(),
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"
);

assert_eq!(
U256Wrapper(uint!(
0x036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0_U256
))
.to_hex_string(),
"0x036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0"
);
}
}

0 comments on commit 30bf785

Please sign in to comment.