diff --git a/Cargo.toml b/Cargo.toml index a0d03ffbe8..9cf51cc221 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ exclude = [ "flooder", "fork-off", "relations", + "poseidon", ] [profile.release] diff --git a/poseidon/Cargo.lock b/poseidon/Cargo.lock new file mode 100644 index 0000000000..6e449a7020 --- /dev/null +++ b/poseidon/Cargo.lock @@ -0,0 +1,624 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" + +[[package]] +name = "ark-bls12-381" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65be532f9dd1e98ad0150b037276cde464c6f371059e6dd02c0222395761f6aa" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea978406c4b1ca13c2db2373b05cc55429c3575b8b21f1b9ee859aa5b03dd42" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn", +] + +[[package]] +name = "ark-nonnative-field" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "440ad4569974910adbeb84422b7e622b79e08d27142afd113785b7fcfb446186" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-r1cs-std", + "ark-relations", + "ark-std", + "derivative", + "num-bigint", + "num-integer", + "num-traits", + "tracing", +] + +[[package]] +name = "ark-r1cs-std" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e8fdacb1931f238a0d866ced1e916a49d36de832fd8b83dc916b718ae72893" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-relations", + "ark-std", + "derivative", + "num-bigint", + "num-traits", + "tracing", +] + +[[package]] +name = "ark-relations" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cba4c1c99792a6834bd97f7fd76578ec2cd58d2afc5139a17e1d1bec65b38f6" +dependencies = [ + "ark-ff", + "ark-std", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std", + "digest", +] + +[[package]] +name = "ark-sponge" +version = "0.3.0" +source = "git+https://github.com/penumbra-zone/sponge?branch=r1cs#113469aef48a9c5f458dbf523a509d4769affbf2" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-nonnative-field", + "ark-r1cs-std", + "ark-relations", + "ark-serialize", + "ark-std", + "derivative", + "digest", + "rand_chacha", + "tracing", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "keccak" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core", + "zeroize", +] + +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" + +[[package]] +name = "paste" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" + +[[package]] +name = "pest" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f6e86fb9e7026527a0d46bc308b841d73170ef8f443e1807f6ef88526a816d4" +dependencies = [ + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "poseidon" +version = "0.1.0" +dependencies = [ + "ark-bls12-381", + "ark-ff", + "ark-r1cs-std", + "ark-relations", + "ark-sponge", + "ark-std", + "once_cell", + "poseidon-paramgen", + "poseidon-permutation", +] + +[[package]] +name = "poseidon-paramgen" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aaee7da4206270e6530bc1ec1ff1d930f67239396412c2a1c13e200daf88eaa" +dependencies = [ + "anyhow", + "ark-ff", + "merlin", + "num", + "num-bigint", + "rand_core", +] + +[[package]] +name = "poseidon-permutation" +version = "0.1.0" +source = "git+https://github.com/penumbra-zone/poseidon377#a2d8c7a3288e2e877ac88a4d8fd3cc4ff2b52c04" +dependencies = [ + "ark-ff", + "once_cell", + "poseidon-paramgen", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "thiserror" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/poseidon/Cargo.toml b/poseidon/Cargo.toml new file mode 100644 index 0000000000..7cf4ed7b2b --- /dev/null +++ b/poseidon/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "poseidon" +version = "0.1.0" +edition = "2021" +license = "Apache 2.0" +authors = ["Cardinal Cryptography"] +description = "An instantiation of the Poseidon SNARK-friendly hash function." + +[dependencies] +ark-bls12-381 = { version = "^0.3.0" } +ark-ff = { version = "^0.3.0", default-features = false } +ark-r1cs-std = {version = "^0.3.0" , default-features = false } +ark-relations = { version = "^0.3.0", default-features = false } +ark-sponge = { git = "https://github.com/penumbra-zone/sponge", branch = "r1cs", default-features = false, features = ["r1cs"] } +once_cell = "1.8" +poseidon-paramgen = { version = "0.1", default-features = false } +poseidon-permutation = { git = "https://github.com/penumbra-zone/poseidon377", default-features = false } +ark-std = { version = "^0.3.0", default-features = false } + +[build-dependencies] +ark-bls12-381 = { version = "^0.3.0" } +ark-ff = { version = "^0.3.0" } +poseidon-paramgen = { version = "0.1" } +ark-std = { version = "^0.3.0" } + +[features] +default = ["std"] +std = [ + "ark-bls12-381/std", + "ark-ff/std", + "ark-r1cs-std/std", + "ark-relations/std", + "ark-sponge/std", +] diff --git a/poseidon/build.rs b/poseidon/build.rs new file mode 100644 index 0000000000..c1613290be --- /dev/null +++ b/poseidon/build.rs @@ -0,0 +1,42 @@ +use std::{ + env, + fs::File, + io::{BufWriter, Write}, + path::PathBuf, +}; + +use ark_bls12_381::{Fr, FrParameters}; +use ark_ff::fields::FpParameters; +use ark_std::vec; +use poseidon_paramgen::poseidon_build; + +fn main() { + let security_level = match env::var("SECURITY_LEVEL") { + Ok(level) => match level.as_str() { + "80" => 80, + "128" => 128, + "256" => 256, + _ => panic!("Unsupported security level. Supported levels: 80, 128, 256"), + }, + Err(_) => 128, + }; + + // t = arity + 1, so t=2 is a 1:1 hash, t=3 is a 2:1 hash etc + // see https://spec.filecoin.io/#section-algorithms.crypto.poseidon.filecoins-poseidon-instances for similar specification used by Filecoin + let t_values = vec![2]; + + // Fr => Fp256 + let parameters = + poseidon_build::compile::(security_level, t_values, FrParameters::MODULUS, true); + + let output_directory = PathBuf::from( + env::var("OUT_DIR").expect("OUT_DIR environmental variable should be always set"), + ) + .join("parameters.rs"); + + let mut file = + BufWriter::new(File::create(output_directory).expect("can't create source file")); + + file.write_all(parameters.as_bytes()) + .expect("can write parameters to file"); +} diff --git a/poseidon/src/lib.rs b/poseidon/src/lib.rs new file mode 100644 index 0000000000..a7ad413f4e --- /dev/null +++ b/poseidon/src/lib.rs @@ -0,0 +1,54 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use ark_bls12_381::Fr; +use once_cell::sync::Lazy; +mod parameters; + +type CircuitField = ark_bls12_381::Fr; +type FpVar = ark_r1cs_std::fields::fp::FpVar; + +// Poseidon paper suggests using domain separation for concretely encoding the use case in the capacity element (which is fine as it is 256 bits large and has a lot of bits to fill) +pub static DOMAIN_SEPARATOR: Lazy = Lazy::new(|| Fr::from(2137)); + +pub mod hash { + use ark_bls12_381::Fr; + use ark_std::vec; + use poseidon_permutation::Instance; + + use super::DOMAIN_SEPARATOR; + use crate::parameters::RATE_1_PARAMETERS; + /// hashes one field value, outputs a fixed length field value + pub fn one_to_one_hash(value: Fr) -> Fr { + let parameters = RATE_1_PARAMETERS.clone(); + let mut state = Instance::new(¶meters); + state.n_to_1_fixed_hash(vec![*DOMAIN_SEPARATOR, value]) + } +} + +pub mod circuit { + use ark_bls12_381::Fr; + use ark_r1cs_std::prelude::AllocVar; + use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; + use ark_sponge::{ + constraints::CryptographicSpongeVar, poseidon::constraints::PoseidonSpongeVar, + }; + use ark_std::vec; + + use super::{FpVar, DOMAIN_SEPARATOR}; + use crate::parameters::{to_ark_sponge_poseidon_parameters, RATE_1_PARAMETERS}; + + /// hashes one field value inside the circuit + pub fn one_to_one_hash( + cs: ConstraintSystemRef, + value: FpVar, + ) -> Result { + let mut state: PoseidonSpongeVar = PoseidonSpongeVar::new( + cs.clone(), + &to_ark_sponge_poseidon_parameters(RATE_1_PARAMETERS.clone()), + ); + let domain_separator = FpVar::new_constant(cs, *DOMAIN_SEPARATOR)?; + state.absorb(&vec![domain_separator, value])?; + let result = state.squeeze_field_elements(1)?; + Ok(result[0].clone()) + } +} diff --git a/poseidon/src/parameters.rs b/poseidon/src/parameters.rs new file mode 100644 index 0000000000..b3850bf414 --- /dev/null +++ b/poseidon/src/parameters.rs @@ -0,0 +1,37 @@ +use ark_bls12_381::Fr; +use ark_sponge::poseidon::PoseidonParameters as ArkSpongePoseidonParameters; +use once_cell::sync::Lazy; +use poseidon_paramgen::{Alpha, PoseidonParameters}; + +// Poseidon parameters generated for the Fr (Fp256) finite field +pub mod fr_parameters { + use ark_std::vec; + include!(concat!(env!("OUT_DIR"), "/parameters.rs")); +} + +// Parameters for the 1:1 hash instance of Poseidon +pub static RATE_1_PARAMETERS: Lazy> = Lazy::new(fr_parameters::rate_1); + +// taken from Penumbra (https://github.com/penumbra-zone/poseidon377/blob/a2d8c7a3288e2e877ac88a4d8fd3cc4ff2b52c04/poseidon377/src/r1cs.rs#L12) +pub(crate) fn to_ark_sponge_poseidon_parameters( + params: PoseidonParameters, +) -> ArkSpongePoseidonParameters { + let alpha = match params.alpha { + Alpha::Exponent(exp) => exp as u64, + Alpha::Inverse => panic!("ark-sponge does not allow inverse alpha"), + }; + let capacity = 1; + let rate = params.t - capacity; + let full_rounds = params.rounds.full(); + let partial_rounds = params.rounds.partial(); + + ArkSpongePoseidonParameters { + full_rounds, + partial_rounds, + alpha, + ark: params.arc.into(), + mds: params.mds.into(), + rate, + capacity, + } +} diff --git a/relations/Cargo.lock b/relations/Cargo.lock index d4836d051e..e22380d9f8 100644 --- a/relations/Cargo.lock +++ b/relations/Cargo.lock @@ -13,6 +13,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "anyhow" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" + [[package]] name = "ark-bls12-381" version = "0.3.0" @@ -268,6 +274,24 @@ dependencies = [ "ark-std", ] +[[package]] +name = "ark-sponge" +version = "0.3.0" +source = "git+https://github.com/penumbra-zone/sponge?branch=r1cs#113469aef48a9c5f458dbf523a509d4769affbf2" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-nonnative-field", + "ark-r1cs-std", + "ark-relations", + "ark-serialize", + "ark-std", + "derivative", + "digest", + "rand_chacha", + "tracing", +] + [[package]] name = "ark-std" version = "0.3.0" @@ -295,12 +319,27 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + [[package]] name = "crypto-mac" version = "0.8.0" @@ -361,12 +400,47 @@ dependencies = [ "ahash", ] +[[package]] +name = "keccak" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] + [[package]] name = "libc" version = "0.2.138" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core", + "zeroize", +] + +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -378,6 +452,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +dependencies = [ + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -388,6 +471,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -431,6 +537,45 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +[[package]] +name = "poseidon" +version = "0.1.0" +dependencies = [ + "ark-bls12-381", + "ark-ff", + "ark-r1cs-std", + "ark-relations", + "ark-sponge", + "ark-std", + "once_cell", + "poseidon-paramgen", + "poseidon-permutation", +] + +[[package]] +name = "poseidon-paramgen" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aaee7da4206270e6530bc1ec1ff1d930f67239396412c2a1c13e200daf88eaa" +dependencies = [ + "anyhow", + "ark-ff", + "merlin", + "num", + "num-bigint", + "rand_core", +] + +[[package]] +name = "poseidon-permutation" +version = "0.1.0" +source = "git+https://github.com/penumbra-zone/poseidon377#a2d8c7a3288e2e877ac88a4d8fd3cc4ff2b52c04" +dependencies = [ + "ark-ff", + "once_cell", + "poseidon-paramgen", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -480,6 +625,9 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] [[package]] name = "relations" @@ -501,6 +649,7 @@ dependencies = [ "ark-snark", "ark-std", "blake2", + "poseidon", ] [[package]] diff --git a/relations/Cargo.toml b/relations/Cargo.toml index 1fcdb0e709..9fd6015efa 100644 --- a/relations/Cargo.toml +++ b/relations/Cargo.toml @@ -22,6 +22,7 @@ ark-serialize = { version = "^0.3.0", default-features = false } ark-snark = { version = "^0.3.0", default-features = false } ark-std = { version = "^0.3.0", default-features = false } blake2 = { version = "0.9.2", default-features = false } +poseidon = { path = "../poseidon", default-features = false } [features] default = ["std"] @@ -40,4 +41,5 @@ std = [ "ark-relations/std", "ark-serialize/std", "blake2/std", + "poseidon/std", ] diff --git a/relations/src/environment.rs b/relations/src/environment.rs index 2c892c305e..9c56214b6e 100644 --- a/relations/src/environment.rs +++ b/relations/src/environment.rs @@ -14,6 +14,8 @@ use blake2::Blake2s; pub type PairingEngine = ark_bls12_381::Bls12_381; /// Common scalar field. pub type CircuitField = ark_bls12_381::Fr; +/// variable in the Fr field +pub type FpVar = ark_r1cs_std::fields::fp::FpVar; // Systems with hardcoded parameters. pub type Groth16 = ark_groth16::Groth16; diff --git a/relations/src/lib.rs b/relations/src/lib.rs index 95a3c9a9ca..630745ea82 100644 --- a/relations/src/lib.rs +++ b/relations/src/lib.rs @@ -3,6 +3,7 @@ mod environment; mod linear; mod merkle_tree; +mod preimage; mod relation; mod serialization; mod shielder; @@ -17,6 +18,7 @@ pub use environment::{ }; pub use linear::LinearEquationRelation; pub use merkle_tree::{MerkleTreeRelation, Root}; +pub use preimage::PreimageRelation; pub use relation::GetPublicInput; pub use serialization::serialize; pub use shielder::{ diff --git a/relations/src/preimage.rs b/relations/src/preimage.rs new file mode 100644 index 0000000000..42200a5238 --- /dev/null +++ b/relations/src/preimage.rs @@ -0,0 +1,148 @@ +// This relation showcases how to use Poseidon in r1cs circuits +use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget}; +use ark_relations::{ + ns, + r1cs::{ + ConstraintSynthesizer, ConstraintSystemRef, SynthesisError, + SynthesisError::AssignmentMissing, + }, +}; +use ark_std::{marker::PhantomData, vec, vec::Vec}; +use poseidon::circuit; + +use crate::{ + environment::FpVar, + relation::state::{FullInput, NoInput, OnlyPublicInput, State, WithPublicInput}, + CircuitField, GetPublicInput, +}; + +/// Preimage relation : H(preimage)=hash +/// where: +/// - hash : public input +/// - preimage : private witness +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub struct PreimageRelation { + // private witness + pub preimage: Option, + // public input + pub hash: Option, + _phantom: PhantomData, +} + +impl PreimageRelation { + pub fn without_input() -> Self { + Self { + hash: None, + preimage: None, + _phantom: PhantomData, + } + } +} + +impl PreimageRelation { + pub fn with_public_input(hash: CircuitField) -> Self { + Self { + preimage: None, + hash: Some(hash), + _phantom: PhantomData, + } + } +} + +impl PreimageRelation { + pub fn with_full_input(preimage: CircuitField, hash: CircuitField) -> Self { + Self { + preimage: Some(preimage), + hash: Some(hash), + _phantom: PhantomData, + } + } +} + +impl ConstraintSynthesizer for PreimageRelation { + fn generate_constraints( + self, + cs: ConstraintSystemRef, + ) -> Result<(), SynthesisError> { + let preimage = FpVar::new_witness(ns!(cs, "preimage"), || { + self.preimage.ok_or(AssignmentMissing) + })?; + let hash = FpVar::new_input(ns!(cs, "hash"), || self.hash.ok_or(AssignmentMissing))?; + let hash_result = circuit::one_to_one_hash(cs, preimage)?; + + hash.enforce_equal(&hash_result)?; + + Ok(()) + } +} + +impl GetPublicInput for PreimageRelation { + fn public_input(&self) -> Vec { + vec![self + .hash + .expect("Circuit should have public input assigned")] + } +} + +#[cfg(test)] +mod tests { + use ark_bls12_381::Bls12_381; + use ark_crypto_primitives::SNARK; + use ark_groth16::Groth16; + use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; + use poseidon::hash; + + use super::PreimageRelation; + use crate::{CircuitField, GetPublicInput}; + + #[test] + fn preimage_constraints_correctness() { + let preimage = CircuitField::from(17u64); + let image = hash::one_to_one_hash(preimage); + + let circuit = PreimageRelation::with_full_input(preimage, image); + + let cs = ConstraintSystem::new_ref(); + circuit.generate_constraints(cs.clone()).unwrap(); + + let is_satisfied = cs.is_satisfied().unwrap(); + if !is_satisfied { + println!("{:?}", cs.which_is_unsatisfied()); + } + + assert!(is_satisfied); + } + + #[test] + fn unsatisfied_preimage_constraints() { + let true_preimage = CircuitField::from(17u64); + let fake_image = hash::one_to_one_hash(CircuitField::from(19u64)); + let circuit = PreimageRelation::with_full_input(true_preimage, fake_image); + + let cs = ConstraintSystem::new_ref(); + circuit.generate_constraints(cs.clone()).unwrap(); + + let is_satisfied = cs.is_satisfied().unwrap(); + + assert!(!is_satisfied); + } + + #[test] + fn preimage_proving_and_verifying() { + let preimage = CircuitField::from(7u64); + let image = hash::one_to_one_hash(preimage); + + let circuit = PreimageRelation::with_full_input(preimage, image); + + let mut rng = ark_std::test_rng(); + let (pk, vk) = + Groth16::::circuit_specific_setup(circuit.clone(), &mut rng).unwrap(); + + let input = circuit.public_input(); + + let proof = Groth16::prove(&pk, circuit, &mut rng).unwrap(); + + let is_valid = Groth16::verify(&vk, &input, &proof).unwrap(); + assert!(is_valid); + } +} diff --git a/relations/src/relation.rs b/relations/src/relation.rs index 8da2158cea..87cef7613d 100644 --- a/relations/src/relation.rs +++ b/relations/src/relation.rs @@ -9,8 +9,11 @@ pub trait GetPublicInput { } pub(super) mod state { + #[derive(Clone, Debug)] pub enum NoInput {} + #[derive(Clone, Debug)] pub enum OnlyPublicInput {} + #[derive(Clone, Debug)] pub enum FullInput {} pub trait State {} diff --git a/relations/src/shielder/deposit.rs b/relations/src/shielder/deposit.rs index 3921904f8c..feb0414eeb 100644 --- a/relations/src/shielder/deposit.rs +++ b/relations/src/shielder/deposit.rs @@ -12,12 +12,12 @@ use ark_std::{marker::PhantomData, vec, vec::Vec}; use super::{ note::check_note, types::{ - BackendNote, BackendNullifier, BackendTokenAmount, BackendTokenId, BackendTrapdoor, FpVar, + BackendNote, BackendNullifier, BackendTokenAmount, BackendTokenId, BackendTrapdoor, FrontendNote, FrontendNullifier, FrontendTokenAmount, FrontendTokenId, FrontendTrapdoor, }, }; use crate::{ - environment::CircuitField, + environment::{CircuitField, FpVar}, relation::{ state::{FullInput, NoInput, OnlyPublicInput, State, WithPublicInput}, GetPublicInput, diff --git a/relations/src/shielder/note.rs b/relations/src/shielder/note.rs index 5989241d28..a89b875291 100644 --- a/relations/src/shielder/note.rs +++ b/relations/src/shielder/note.rs @@ -8,10 +8,11 @@ use ark_std::{vec, vec::Vec}; use super::{ tangle::{tangle, tangle_in_field}, types::{ - ByteVar, FpVar, FrontendNote, FrontendNullifier, FrontendTokenAmount, FrontendTokenId, + ByteVar, FrontendNote, FrontendNullifier, FrontendTokenAmount, FrontendTokenId, FrontendTrapdoor, }, }; +use crate::environment::FpVar; /// Verify that `note` is indeed the result of tangling `(token_id, token_amount, trapdoor, /// nullifier)`. diff --git a/relations/src/shielder/types.rs b/relations/src/shielder/types.rs index f1f1a0d438..1ade059181 100644 --- a/relations/src/shielder/types.rs +++ b/relations/src/shielder/types.rs @@ -4,8 +4,6 @@ use ark_std::vec::Vec; use crate::environment::CircuitField; -/// The circuit lifting for `CircuitField`. -pub type FpVar = ark_r1cs_std::fields::fp::FpVar; /// The circuit lifting for the byte type. pub type ByteVar = ark_r1cs_std::uint8::UInt8; diff --git a/relations/src/shielder/withdraw.rs b/relations/src/shielder/withdraw.rs index 96bac8bb2f..36cf5c2e8c 100644 --- a/relations/src/shielder/withdraw.rs +++ b/relations/src/shielder/withdraw.rs @@ -16,13 +16,13 @@ use super::{ tangle::tangle_in_field, types::{ BackendAccount, BackendLeafIndex, BackendMerklePath, BackendMerkleRoot, BackendNote, - BackendNullifier, BackendTokenAmount, BackendTokenId, BackendTrapdoor, ByteVar, FpVar, + BackendNullifier, BackendTokenAmount, BackendTokenId, BackendTrapdoor, ByteVar, FrontendAccount, FrontendLeafIndex, FrontendMerklePath, FrontendMerkleRoot, FrontendNote, FrontendNullifier, FrontendTokenAmount, FrontendTokenId, FrontendTrapdoor, }, }; use crate::{ - environment::CircuitField, + environment::{CircuitField, FpVar}, relation::{ state::{FullInput, NoInput, OnlyPublicInput, State, WithPublicInput}, GetPublicInput,