Skip to content

Commit

Permalink
Merge pull request #249 from dusk-network/mocello/safe
Browse files Browse the repository at this point in the history
Use SAFE framework for sponge design
  • Loading branch information
moCello authored Mar 6, 2024
2 parents 0194b0f + 08ff42b commit 119128a
Show file tree
Hide file tree
Showing 25 changed files with 940 additions and 886 deletions.
8 changes: 1 addition & 7 deletions .github/workflows/dusk_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@ jobs:
- uses: Swatinem/rust-cache@v2
- run: cargo bench --features=cipher,zk --no-run

check_merkle:
name: Check merkle compiles without zk
uses: dusk-network/.github/.github/workflows/run-tests.yml@main
with:
test_flags: --features=merkle --no-run

check_cipher:
name: Check cipher compiles without zk
uses: dusk-network/.github/.github/workflows/run-tests.yml@main
Expand All @@ -42,4 +36,4 @@ jobs:
name: Tests all
uses: dusk-network/.github/.github/workflows/run-tests.yml@main
with:
test_flags: --features=zk,cipher,merkle,rkyv-impl,size_32
test_flags: --features=zk,cipher,rkyv-impl,size_32
18 changes: 17 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add `Hash` struct [#202]

### Changed

- Refactor code with the introduction of SAFE framework [#248]

### Removed

- Remove `perm_uses` module as it is obsolete with the introduction of SAFE [#248]
- Remove `merkle` feature with the introduction of SAFE [#248]

## [0.35.0] - 2024-02-28

### Changed

- Rename trait `hades::Strategy` to `hades::Permutation` [#243]
- Rename struct `hades::ScalarStrategy` to `hades::ScalarPermutation` [#243]
- Rename struct `hades::GadgetStrategy` to `hades::GadgetPermutaiton` [#243]
- Rename struct `hades::GadgetStrategy` to `hades::GadgetPermutation` [#243]
- Reduce the number of `ROUND_CONSTANTS` from 960 to 335 [#246]
- Remove the constants iterator in favor of indexing the constants array directly [#246]
- Change `ROUND_CONSTANTS` into a two-dimensional array [#246]
Expand All @@ -28,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Add the code for the hades permutation to crate [#240]
- Add internal `permute` and `permute_gadget` functions to `hades` module [#243]
- Add SAFE dependency [#248]

## [0.34.0] - 2024-01-24

Expand Down Expand Up @@ -451,13 +465,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Variants of sponge for `Scalar` & `Gadget(Variable/LC)`.

<!-- ISSUES -->
[#248]: https://github.com/dusk-network/poseidon252/issues/248
[#246]: https://github.com/dusk-network/poseidon252/issues/246
[#243]: https://github.com/dusk-network/poseidon252/issues/243
[#240]: https://github.com/dusk-network/poseidon252/issues/240
[#215]: https://github.com/dusk-network/poseidon252/issues/215
[#212]: https://github.com/dusk-network/poseidon252/issues/212
[#206]: https://github.com/dusk-network/poseidon252/issues/206
[#203]: https://github.com/dusk-network/poseidon252/issues/203
[#202]: https://github.com/dusk-network/poseidon252/issues/202
[#200]: https://github.com/dusk-network/poseidon252/issues/200
[#198]: https://github.com/dusk-network/poseidon252/issues/198
[#197]: https://github.com/dusk-network/Poseidon252/issues/197
Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,20 @@ dusk-bls12_381 = { version = "0.13", default-features = false }
dusk-jubjub = { version = "0.14", default-features = false }
dusk-bytes = "0.1"
dusk-plonk = { version = "0.19", default-features = false, features = ["alloc"], optional = true }
dusk-safe = "0.1"
rkyv = { version = "0.7", optional = true, default-features = false }
bytecheck = { version = "0.6", optional = true, default-features = false }

[dev-dependencies]
criterion = "0.3"
rand = { version = "0.8", default-features = false, features = ["getrandom", "std_rng"] }
ff = { version = "0.13", default-features = false }
once_cell = "1"

[features]
zk = [
"dusk-plonk",
]
merkle = []
cipher = []
size_16 = ["rkyv/size_16"]
size_32 = ["rkyv/size_32"]
Expand Down Expand Up @@ -58,7 +59,7 @@ incremental = false
codegen-units = 1

[[bench]]
name = "sponge"
name = "hash"
harness = false
required-features = ["zk"]

Expand Down
66 changes: 32 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,62 +6,60 @@

Reference implementation for the Poseidon Hashing algorithm.

#### Reference

Reference:
[Starkad and Poseidon: New Hash Functions for Zero Knowledge Proof Systems](https://eprint.iacr.org/2019/458.pdf)

This repository has been created so there's a unique library that holds the tools & functions
required to perform Poseidon Hashes.
This repository has been created so there's a unique library that holds the tools & functions required to perform Poseidon Hashes on field elements of the bls12-381 elliptic curve.

These hashes heavily rely on the Hades design for its inner permutation.
The hash uses the Hades design for its inner permutation and the [SAFE](https://eprint.iacr.org/2023/522.pdf) framework for contstructing the sponge.

**The library provides the two hashing techniques of Poseidon:**
The library provides the two hashing techniques of Poseidon:
- The 'normal' hashing functionalities operating on `BlsScalar`.
- The 'gadget' hashing functionalities that build a circuit which outputs the hash.

## Sponge Hash
## Example

The `Sponge` technique in Poseidon allows to hash an unlimited amount of data
into a single `Scalar`.
The sponge hash technique requires a padding to be applied before the data can
be hashed.
```rust
use rand::rngs::StdRng;
use rand::SeedableRng;

This is done to avoid hash collisions as stated in the paper of the Poseidon Hash
algorithm. See: <https://eprint.iacr.org/2019/458.pdf>.
The inputs of the `sponge_hash` are always `Scalar` or need to be capable of being represented
as it.
use dusk_poseidon::{Domain, Hash};
use dusk_bls12_381::BlsScalar;
use ff::Field;

The module provides two sponge hash implementations:
// generate random input
let mut rng = StdRng::seed_from_u64(0xbeef);
let mut input = [BlsScalar::zero(); 42];
for scalar in input.iter_mut() {
*scalar = BlsScalar::random(&mut rng);
}

- Sponge hash using `Scalar` as backend. Which hashes the inputted `Scalar`s and returns a single
`Scalar`.
// digest the input all at once
let hash = Hash::digest(Domain::Other, &input);

- Sponge hash gadget using `dusk_plonk::Witness` as a backend. This technique is used/required
when you want to proof pre-images of unconstrained data inside Zero-Knowledge PLONK circuits.
// update the input gradually
let mut hasher = Hash::new(Domain::Other);
hasher.update(&input[..3]);
hasher.update(&input[3..]);
assert_eq!(hash, hasher.finalize());

## Documentation
// create a hash used for merkle tree hashing with arity = 4
let merkle_hash = Hash::digest(Domain::Merkle4, &input[..4]);

This crate contains info about all the functions that the library provides as well as the
documentation regarding the data structures that it exports. To check it, please feel free to go to
the [documentation page](https://dusk-network.github.io/Poseidon252/poseidon252/index.html)
// which is different when another domain is used
assert_ne!(merkle_hash, Hash::digest(Domain::Other, &input[..4]));
```

## Benchmarks

There are benchmarks for `sponge` and `cipher` in their native form, operating on `Scalar`, and as a zero-knowledge gadget, using `Witness`.

To run all benchmarks on your machine, run
```shell
cargo bench
cargo bench --features=zk,cipher
```
in the repository.

To run a specific benchmark, run
```shell
cargo bench --bench <name>
```
where you replace `<name>` with the benchmark name. For example to run the benchmarks for the poseidon cipher encription from the file 'benches/cipher_encrypt.rs', you would need to run
```shell
cargo bench --benches cipher_encrypt
```

## Licensing

This code is licensed under Mozilla Public License Version 2.0 (MPL-2.0). Please see [LICENSE](https://github.com/dusk-network/plonk/blob/master/LICENSE) for further info.
Expand Down
2 changes: 1 addition & 1 deletion assets/HOWTO.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::fs;
use std::io::Write;

// The amount of constants generated, this needs to be at least the total number
// of rounds (= 59 + 8) multiplied by the width of the permutaiton array (= 5).
// of rounds (= 59 + 8) multiplied by the width of the permutation array (= 5).
const CONSTANTS: usize = (59 + 8) * 5;

fn constants() -> [BlsScalar; CONSTANTS] {
Expand Down
4 changes: 2 additions & 2 deletions benches/cipher_decrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// Copyright (c) DUSK NETWORK. All rights reserved.

use dusk_poseidon::cipher::{self, PoseidonCipher};
use dusk_poseidon::{decrypt_gadget, PoseidonCipher};

use criterion::{black_box, criterion_group, criterion_main, Criterion};
use dusk_jubjub::GENERATOR;
Expand Down Expand Up @@ -59,7 +59,7 @@ impl Circuit for CipherDecrypt {
*cipher_witness = composer.append_witness(*cipher_scalar);
});

cipher::decrypt(composer, &shared, nonce, &cipher_circuit);
decrypt_gadget(composer, &shared, nonce, &cipher_circuit);

Ok(())
}
Expand Down
4 changes: 2 additions & 2 deletions benches/cipher_encrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// Copyright (c) DUSK NETWORK. All rights reserved.

use dusk_poseidon::cipher::{self, PoseidonCipher};
use dusk_poseidon::{encrypt_gadget, PoseidonCipher};

use criterion::{black_box, criterion_group, criterion_main, Criterion};
use dusk_jubjub::GENERATOR;
Expand Down Expand Up @@ -56,7 +56,7 @@ impl Circuit for CipherEncrypt {
*message_witness = composer.append_witness(*message_scalar);
});

cipher::encrypt(composer, &shared, nonce, &message_circuit);
encrypt_gadget(composer, &shared, nonce, &message_circuit);

Ok(())
}
Expand Down
27 changes: 17 additions & 10 deletions benches/sponge.rs → benches/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use criterion::{black_box, criterion_group, criterion_main, Criterion};
use dusk_plonk::prelude::*;
use dusk_poseidon::hades::WIDTH;
use dusk_poseidon::{Domain, Hash, HashGadget, HADES_WIDTH};
use ff::Field;
use rand::rngs::StdRng;
use rand::SeedableRng;
Expand All @@ -15,26 +15,33 @@ const CAPACITY: usize = 11;

#[derive(Default)]
struct SpongeCircuit {
message: [BlsScalar; WIDTH],
message: [BlsScalar; HADES_WIDTH - 1],
output: BlsScalar,
}

impl SpongeCircuit {
pub fn new(message: [BlsScalar; WIDTH]) -> Self {
SpongeCircuit { message }
pub fn new(
message: [BlsScalar; HADES_WIDTH - 1],
output: BlsScalar,
) -> Self {
SpongeCircuit { message, output }
}
}

impl Circuit for SpongeCircuit {
fn circuit(&self, composer: &mut Composer) -> Result<(), Error> {
let mut w_message = [Composer::ZERO; WIDTH];
let mut w_message = [Composer::ZERO; HADES_WIDTH - 1];
w_message
.iter_mut()
.zip(self.message)
.for_each(|(witness, scalar)| {
*witness = composer.append_witness(scalar);
});

dusk_poseidon::sponge::gadget(composer, &w_message);
let output_witness =
HashGadget::digest(Domain::Merkle4, composer, &w_message)
.expect("creating the hash should not fail");
composer.assert_equal_constant(output_witness[0], 0, Some(self.output));

Ok(())
}
Expand All @@ -49,20 +56,20 @@ fn bench_sponge(c: &mut Criterion) {
let (prover, verifier) = Compiler::compile::<SpongeCircuit>(&pp, label)
.expect("Circuit should compile successfully");
let mut proof = Proof::default();
let public_inputs = Vec::new();
let message = [
BlsScalar::random(&mut rng),
BlsScalar::random(&mut rng),
BlsScalar::random(&mut rng),
BlsScalar::random(&mut rng),
BlsScalar::random(&mut rng),
];
let circuit = SpongeCircuit::new(message);
let public_inputs = Hash::digest(Domain::Merkle4, &message)
.expect("creating the hash should not fail");
let circuit = SpongeCircuit::new(message, public_inputs[0]);

// Benchmark sponge native
c.bench_function("sponge native", |b| {
b.iter(|| {
dusk_poseidon::sponge::hash(black_box(&circuit.message));
let _ = Hash::digest(Domain::Merkle4, black_box(&circuit.message));
})
});

Expand Down
Loading

0 comments on commit 119128a

Please sign in to comment.