Skip to content
NovaCorpAIPublic

About

Veil: pago privado no rastreable en Stellar testnet (privacy pool Circom/Groth16 + Soroban BN254)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Veil — pago privado no rastreable en Stellar testnet

Privacy pool estilo Tornado en Soroban: depósito fijo de 10 XLM, commitment en un Merkle tree Poseidon (16 niveles), retiro con prueba Groth16 (BN254) + nullifier. Ver PRD.md y CLAUDE.md.

Estado: ✅ desplegado y verificado en testnet

Página de demo: https://veil.agentposhq.com (alias: https://veil-lime-alpha.vercel.app) · código: https://github.com/NovaCorpAI/veil

Qué Valor
Contract ID CA4D3V4DB6FPXM4K7WAOG4LHOI5L7Q6R2EI4CENKZKQGER5VUG3CL6QQ · stellar.expert
Token SAC XLM nativo CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC
init tx 528f08c2…
deposit (alice, 10 XLM) 4b1a171b…
withdraw (carol → dave, prueba ZK) 188ac2f9…
corrida 2 (con OpenRouter): deposit / withdraw b54d05bb… / b5297ecc… · asesor IA: "riesgo medio, esperar más depósitos"
segundo withdraw con la misma nota rechazado en simulación: Error(Contract, #5) = NullifierSpent

Un observador ve: alice → pool (10 XLM) y pool → dave (10 XLM) firmado por carol. Nada vincula las dos txs: el retiro solo expone root, nullifierHash y recipient, y la prueba Groth16 demuestra que existe un commitment en el árbol sin revelar cuál.

Cuentas testnet

  • alice (depositante): GAJJUTIVOWTTHL73PFPSBNSNMJJZY3EFTTLW7VLVP4LDVA4KXGKYRMVX
  • carol (firma el retiro): GACFTWXM6RWGB5PDVFRCTBC5T3K6MS7NHKXMLGO3JPD6YH7IN6KZ3RLD
  • dave (destinatario): GDN5MJPTUSOEAMXMFD3LTYIG7JP4Z7UI746YQHLPK4QATSHZPDKGO2GA

Para jueces: tres niveles de verificación

Nivel 1 · sin instalar nada (2 min). Abrir el contrato en stellar.expert: hay 2 deposit y 2 withdraw. En cada withdraw, los args son la prueba (A, B, C), la raíz, el nullifierHash y el destinatario; la tx solo tuvo éxito porque el pairing_check BN254 pasó dentro del contrato. Las cuentas que firman (alice deposita, carol retira) no tienen relación on-chain. https://veil.agentposhq.com muestra lo mismo en vivo.

Nivel 2 · tests del contrato (5 min, solo Rust). cd contracts && cargo test. Cuatro tests: Poseidon(1,2) == circomlib, recipient→Fr igual que el cliente, una prueba real de snarkjs (src/test_fixture.rs) verifica con el pairing BN254 y una alterada no, y el flujo completo deposit → withdraw → doble gasto rechazado con un SAC en el env de pruebas.

Nivel 3 · demo contra el contrato desplegado (10 min). Necesita Node 20+, la Stellar CLI y cuentas de testnet; no necesita Rust ni circom porque el wasm, el zkey y la VK ya están en el repo.

npm i
stellar keys generate alice --network testnet --fund
stellar keys generate carol --network testnet --fund
stellar keys generate dave  --network testnet --fund
cp .env.example .env            # opcional: OPENROUTER_API_KEY; sin key el paso de IA usa un stub
STELLAR=$(which stellar) bash scripts/demo.sh

Eso hace un depósito nuevo desde tu alice, retira con tu carol hacia tu dave con una prueba generada en tu máquina, e intenta el doble retiro. deploy.json apunta al contrato ya desplegado. Para desplegar uno propio: bash scripts/deploy.sh (requiere Rust + target wasm32v1-none).

Fases

Fase Estado
1 · Circuito ✅ circuits/withdraw.circom (4396 restricciones no lineales), setup Groth16, prueba verificada con snarkjs
2 · Contrato ✅ contracts/veil_pool — 4 tests: Poseidon(1,2) == circomlib, recipient→Fr, prueba real de snarkjs verifica on-chain (pairing BN254), flujo completo deposit/withdraw/doble-gasto
3 · Cliente ✅ client/deposit.js, client/withdraw.js (eventos getEvents → árbol → snarkjs → invoke)
4 · Demo ✅ scripts/demo.sh
IA (requisito) ✅ client/openrouter.js: asesor de privacidad vía OpenRouter antes de cada retiro (key en .env, ver .env.example)

Decisiones técnicas que había que acertar

  • Poseidon on-chain = circomlib: crate soroban-poseidon 28.0.0 (poseidon_hash::<3, Bn254Fr>); test vector Poseidon(1,2) = 0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a ✅ en ambos lados.
  • G2 (snarkjs → host functions): cada coordenada Fp2 va be32(c1) || be32(c0) (formato EIP-197). snarkjs entrega [c0, c1]. Implementado en client/encode.js; el pairing pasó al primer intento.
  • Verificador: pairing_check([-A, alpha, vk_x, C], [B, beta, gamma, delta]) con env.crypto().bn254() (soroban-sdk 28, sin feature extra). VK pegada como constantes en src/vk.rs (generado por client/export-rs.js).
  • recipient como Fr: sha256(XDR del ScVal Address)[0..31] (31 bytes para no exceder el campo), idéntico en client/addr.js y en addr_to_fr del contrato.
  • Árbol: zeros[0] = 0, zeros[i] = H(zeros[i-1], zeros[i-1]), filled_subtrees[16], ring de 30 raíces. Misma convención en client/tree.js (pathIndices[i]=0 ⇒ hoja a la izquierda).

Cómo correr

npm i
bash scripts/build-circuit.sh   # circom + setup Groth16 + prueba de ejemplo + verify
node client/export-rs.js        # regenera vk.rs y test_fixture.rs del contrato
(cd contracts && cargo test)    # 4 tests
bash scripts/deploy.sh          # build wasm, deploy, init → deploy.json
bash scripts/demo.sh            # deposit (alice) → nota → withdraw (carol→dave) → doble retiro rechazado

Uso manual:

node client/deposit.js alice                    # imprime la nota veil-<nullifier>-<secret>
node client/withdraw.js <nota> <G...dest> carol # genera prueba y retira

Toolchain (Windows, sin MSVC)

  • tools/circom.exe 2.2.3, tools/stellar.exe 28.1.0 (no están en PATH; los scripts los invocan por ruta).
  • Rust: toolchain stable-x86_64-pc-windows-gnu (el MSVC no está instalado; el GNU trae linker propio) + wasm32v1-none.
  • soroban-sdk 28.0.0, soroban-poseidon 28.0.0. Testnet corre protocolo 29.
  • Powers of tau: los mirrors públicos del .ptau 2^16 devuelven 403, así que ptau/pot14_final.ptau se generó localmente con snarkjs (2^14 basta: < 2^13 restricciones). Solo demo; no es una ceremonia real.

Entrega y checklist de unlinkability: SOLUTION.md.

Fuera de alcance

Association sets, relayer de fees, montos variables, web UI, mainnet.

About

Veil: pago privado no rastreable en Stellar testnet (privacy pool Circom/Groth16 + Soroban BN254)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages