Skip to content

Commit

Permalink
crypto: create new crate, scratch work
Browse files Browse the repository at this point in the history
Adds asset identifiers and value commitment generator computation.

This commit changes the workspace to use a Penumbra fork of some of the
arkworks crates.  The current change is in the Display impl for Fp* instances.
The fork's `ours` branch is based off of `v0.3.0`, in order to not pick up any
unreleased breaking changes.
  • Loading branch information
hdevalence committed Oct 4, 2021
1 parent 9f6ac72 commit e133018
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/notes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
# - published crates are excluded
# Doing this in one go is useful because the JSON file with search
# indexes is overwritten on each cargo doc invocation.
cargo doc --no-deps -p tendermint -p ark-sponge -p decaf377 -p poseidon377 -p penumbra-proto -p penumbra
cargo doc --no-deps -p tendermint -p ark-sponge -p decaf377 -p poseidon377 -p penumbra-crypto -p penumbra-proto -p penumbra
- name: Move API docs to subdirectory
run: |
if [ -d "firebase-tmp" ]; then rm -rf firebase-tmp; fi
Expand Down
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

members = [
"proto",
"crypto",
"penumbra",
]

[patch.crates-io]
tracing = { git = "https://github.com/tokio-rs/tracing/", branch = "v0.1.x" }
tracing-subscriber = { git = "https://github.com/tokio-rs/tracing/", branch = "v0.1.x" }

# The "ours" branch is based off of v0.3.0
ark-ff = { git = "https://github.com/penumbra-zone/algebra", branch = "ours" }
ark-serialize = { git = "https://github.com/penumbra-zone/algebra", branch = "ours" }
16 changes: 16 additions & 0 deletions crypto/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "penumbra-crypto"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
decaf377 = { git = "https://github.com/penumbra-zone/decaf377" }
poseidon377 = { git = "https://github.com/penumbra-zone/poseidon377" }
hex = "0.4"
blake2b_simd = "0.5"
ark-ff = "0.3"
once_cell = "1.8"
# only needed because ark-ff doesn't display correctly
num-bigint = "0.4"
85 changes: 85 additions & 0 deletions crypto/src/asset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//! Asset types and identifiers.
use ark_ff::fields::PrimeField;
use once_cell::sync::Lazy;

use crate::Fq;

/// An identifier for an IBC asset type.
///
/// This is similar to, but different from, the design in [ADR001]. As in
/// ADR001, a denomination trace is hashed to a fixed-size identifier, but
/// unlike ADR001, we hash to a field element rather than a byte string.
///
/// A denomination trace looks like
///
/// - `denom` (native chain A asset)
/// - `transfer/channelToA/denom` (chain B representation of chain A asset)
/// - `transfer/channelToB/transfer/channelToA/denom` (chain C representation of chain B representation of chain A asset)
///
/// ADR001 defines the IBC asset ID as the SHA-256 hash of the denomination
/// trace. Instead, Penumbra hashes to a field element, so that asset IDs can
/// be more easily used inside of a circuit.
///
/// [ADR001]:
/// https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-001-coin-source-tracing.md
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Id(pub Fq);

impl std::fmt::Debug for Id {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("asset::Id({})", self.0.to_string()))
}
}

// XXX define a DenomTrace structure ?

impl From<&[u8]> for Id {
fn from(slice: &[u8]) -> Id {
// Convert an asset name to an asset ID by hashing to a scalar
Id(Fq::from_le_bytes_mod_order(
// XXX choice of hash function?
blake2b_simd::Params::default()
.personal(b"penumbra.asset")
.hash(slice)
.as_bytes(),
))
}
}

/// The domain separator used to hash asset ids to value generators.
static VALUE_GENERATOR_DOMAIN_SEP: Lazy<Fq> = Lazy::new(|| {
Fq::from_le_bytes_mod_order(blake2b_simd::blake2b(b"penumbra.value.generator").as_bytes())
});

impl Id {
/// Compute the value commitment generator for this asset.
pub fn value_generator(&self) -> decaf377::Element {
use crate::poseidon_hash::hash_1;
let hash = hash_1(&VALUE_GENERATOR_DOMAIN_SEP, self.0);
decaf377::Element::map_to_group_cdh(&hash)
}
}

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

#[test]
fn make_up_some_fake_asset_ids() {
// marked for future deletion
// not really a test, just a way to exercise the code

let pen_trace = b"pen";
let atom_trace = b"HubPort/HubChannel/atom";

let pen_id = Id::from(&pen_trace[..]);
let atom_id = Id::from(&atom_trace[..]);

dbg!(pen_id);
dbg!(atom_id);

dbg!(pen_id.value_generator());
dbg!(atom_id.value_generator());
}
}
5 changes: 5 additions & 0 deletions crypto/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub use decaf377::Fq;

pub mod asset;

mod poseidon_hash;
37 changes: 37 additions & 0 deletions crypto/src/poseidon_hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// XXX move into poseidon377 crate?

use crate::Fq;

use poseidon377::ark_sponge::{
poseidon::PoseidonSponge, CryptographicSponge, FieldBasedCryptographicSponge,
};

pub fn hash_1(domain_separator: &Fq, value: Fq) -> Fq {
// we want to set the capacity to domain_separator and the rate to value,
// then run the sponge and extract the rate. it's a bit hard to do this
// using the ark-sponge api, which is trying to do a higher-level duplex
// construction and doesn't allow access to the underlying sponge

let mut sponge = PoseidonSponge::new(&poseidon377::params::rate_1());

// arkworks sponge api doesn't let us call permute
//
// best we can do now is to look in the source to see how the rate and
// capacity are arranged and try to plumb the functionality we want through
// the higher-level API
//
// arkworks uses (rate || capacity) instead of (capacity || rate)
//
// this also gives incompatible outputs, but let's deal with that later

// set the capacity
assert_eq!(sponge.state.len(), 2);
sponge.state[1] = *domain_separator;

// now use absorb to set the rate (hopefully)
sponge.absorb(&value);
// and squeeze an element
let out_vec = sponge.squeeze_native_field_elements(1);

out_vec.into_iter().next().unwrap()
}
2 changes: 0 additions & 2 deletions penumbra/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ publish = false
# Workspace dependencies
penumbra-proto = { path = "../proto" }
# Penumbra dependencies
decaf377 = { git = "https://github.com/penumbra-zone/decaf377" }
poseidon377 = { git = "https://github.com/penumbra-zone/poseidon377" }
tower-abci = { git = "https://github.com/penumbra-zone/tower-abci/" }
tendermint-proto = { git = "https://github.com/penumbra-zone/tendermint-rs.git", branch = "abci-domain-types" }
tendermint = { git = "https://github.com/penumbra-zone/tendermint-rs.git", branch = "abci-domain-types" }
Expand Down

0 comments on commit e133018

Please sign in to comment.