Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Falcon-512 from sk to pk #239

Closed
wants to merge 43 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
fd3888a
chore: update crate version to v0.8
bobbinth Oct 12, 2023
c2853a5
config: add .editorconfig
hackaugusto Oct 19, 2023
3830843
chore: update main readme
bobbinth Oct 19, 2023
ce4abe2
chore: bump winterfell release to .7
Al-Kindi-0 Oct 24, 2023
739febf
rpo: added conversions for digest
hackaugusto Oct 26, 2023
9f6c605
Merge pull request #202 from 0xPolygonMiden/hacka-rpo-digest-conversions
hackaugusto Oct 26, 2023
977638b
feat: RPX (xHash12) hash function implementation
Al-Kindi-0 Oct 24, 2023
f59b481
docs: added RPX benchmarks
Al-Kindi-0 Oct 26, 2023
539dbfa
Merge pull request #201 from 0xPolygonMiden/al-rpx-hash
bobbinth Oct 26, 2023
3a6d31d
docs: update changelog
bobbinth Oct 26, 2023
7038685
mmr: support arbitrary from/to delta updates
hackaugusto Oct 27, 2023
7d3aed0
mmr: support proofs with older forest versions
hackaugusto Oct 27, 2023
0f90589
mmr: publicly export MmrDelta
hackaugusto Oct 27, 2023
4812403
Merge pull request #207 from 0xPolygonMiden/hacka-export-mmr-delta
bobbinth Oct 27, 2023
6251453
Merge pull request #205 from 0xPolygonMiden/hacka-mmr-arbitrary-delta
bobbinth Oct 27, 2023
1c2cb1b
Merge pull request #206 from 0xPolygonMiden/hacka-mmr-proofs-for-olde…
bobbinth Oct 27, 2023
dc20a00
docs: update bench readme
bobbinth Oct 27, 2023
8683429
Merge pull request #200 from 0xPolygonMiden/al-new-winterfell
bobbinth Oct 29, 2023
806e48b
chore: update changelog
bobbinth Oct 29, 2023
0ce53c4
mmr: support accumulator of older forest versions
hackaugusto Nov 1, 2023
9a24daa
Merge pull request #210 from 0xPolygonMiden/hacka-mmr-accumulator-old…
hackaugusto Nov 1, 2023
cf2ab49
bugfix: TSMT failed to verify empty word for depth 64.
hackaugusto Nov 2, 2023
897ec6c
simple_smt: reduce serialized size, use static hashes of the empty word
hackaugusto Nov 2, 2023
e4c3367
mmr: add into_parts for the peaks
hackaugusto Nov 2, 2023
84a26b6
Merge pull request #213 from 0xPolygonMiden/hacka-simple_smt-use-stat…
hackaugusto Nov 3, 2023
b677952
Merge pull request #214 from 0xPolygonMiden/hacka-mmr-peaks-into-parts
hackaugusto Nov 3, 2023
28a2255
Consuming iterator for RpoDigest
plafer Nov 7, 2023
9f0aaf6
Merge pull request #216 from 0xPolygonMiden/plafer-digest-iter
plafer Nov 7, 2023
2279a5f
feat: memoize Signature polynomial decoding
austinabell Nov 9, 2023
481f801
Merge pull request #219 from austinabell/mem_sig
bobbinth Nov 22, 2023
b848880
simplesmt: bugfix, index must be validated before modifying the tree
hackaugusto Nov 22, 2023
7cd5b25
Merge pull request #223 from 0xPolygonMiden/hacka-simplesmt-invalid-i…
bobbinth Nov 23, 2023
2a7602b
simplesmt: simplify duplicate check
hackaugusto Nov 22, 2023
5f48be8
Introduce `SimpleSmt::with_contiguous_leaves()` (#227)
plafer Nov 27, 2023
3b85fc4
Merge pull request #224 from 0xPolygonMiden/hacka-simplesmt-simplify-…
bobbinth Nov 28, 2023
a7791b4
Remove `ExactSizeIterator` constraint from `SimpleSmt::with_leaves()`…
plafer Nov 28, 2023
e87f98d
MmrPeaks::hash_peaks() returns Digest (#230)
plafer Nov 28, 2023
801befa
Merge pull request #212 from 0xPolygonMiden/hacka-tsmt-bug-fix-empty-…
hackaugusto Dec 4, 2023
9b4430f
Implement `SimpleSmt::set_subtree` (#232)
plafer Dec 5, 2023
a4d211d
serde: for MerklePath, ValuePath, and RootPath
hackaugusto Dec 4, 2023
57f902c
Merge pull request #231 from 0xPolygonMiden/hacka-serde-merklepath
hackaugusto Dec 5, 2023
c1c3036
feat: add generation of pk from sk
Al-Kindi-0 Dec 19, 2023
407dde1
nit: remove export
Al-Kindi-0 Dec 19, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Documentation available at editorconfig.org

root=true

[*]
ident_style = space
ident_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.rs]
max_line_length = 100

[*.md]
trim_trailing_whitespace = false

[*.yml]
ident_size = 2
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.8.0 (TBD)

* Implemented the `PartialMmr` data structure (#195).
* Updated Winterfell dependency to v0.7 (#200)
* Implemented RPX hash function (#201).

## 0.7.1 (2023-10-10)

* Fixed RPO Falcon signature build on Windows.
Expand All @@ -12,7 +18,6 @@
* Implemented benchmarking for `TieredSmt` (#182).
* Added more leaf traversal methods for `MerkleStore` (#185).
* Added SVE acceleration for RPO hash function (#189).
* Implemented the `PartialMmr` datastructure (#195).

## 0.6.0 (2023-06-25)

Expand Down
14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[package]
name = "miden-crypto"
version = "0.7.1"
version = "0.8.0"
description = "Miden Cryptographic primitives"
authors = ["miden contributors"]
readme = "README.md"
license = "MIT"
repository = "https://github.com/0xPolygonMiden/crypto"
documentation = "https://docs.rs/miden-crypto/0.7.1"
documentation = "https://docs.rs/miden-crypto/0.8.0"
categories = ["cryptography", "no-std"]
keywords = ["miden", "crypto", "hash", "merkle"]
edition = "2021"
Expand Down Expand Up @@ -42,16 +42,16 @@ sve = ["std"]
blake3 = { version = "1.5", default-features = false }
clap = { version = "4.4", features = ["derive"], optional = true }
libc = { version = "0.2", default-features = false, optional = true }
rand_utils = { version = "0.6", package = "winter-rand-utils", optional = true }
rand_utils = { version = "0.7", package = "winter-rand-utils", optional = true }
serde = { version = "1.0", features = [ "derive" ], default-features = false, optional = true }
winter_crypto = { version = "0.6", package = "winter-crypto", default-features = false }
winter_math = { version = "0.6", package = "winter-math", default-features = false }
winter_utils = { version = "0.6", package = "winter-utils", default-features = false }
winter_crypto = { version = "0.7", package = "winter-crypto", default-features = false }
winter_math = { version = "0.7", package = "winter-math", default-features = false }
winter_utils = { version = "0.7", package = "winter-utils", default-features = false }

[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
proptest = "1.3"
rand_utils = { version = "0.6", package = "winter-rand-utils" }
rand_utils = { version = "0.7", package = "winter-rand-utils" }

[build-dependencies]
cc = { version = "1.0", features = ["parallel"], optional = true }
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This crate contains cryptographic primitives used in Polygon Miden.

* [BLAKE3](https://github.com/BLAKE3-team/BLAKE3) hash function with 256-bit, 192-bit, or 160-bit output. The 192-bit and 160-bit outputs are obtained by truncating the 256-bit output of the standard BLAKE3.
* [RPO](https://eprint.iacr.org/2022/1577) hash function with 256-bit output. This hash function is an algebraic hash function suitable for recursive STARKs.
* [RPX](https://eprint.iacr.org/2023/1045) hash function with 256-bit output. Similar to RPO, this hash function is suitable for recursive STARKs but it is about 2x faster as compared to RPO.

For performance benchmarks of these hash functions and their comparison to other popular hash functions please see [here](./benches/).

Expand All @@ -16,6 +17,7 @@ For performance benchmarks of these hash functions and their comparison to other
* `MerkleTree`: a regular fully-balanced binary Merkle tree. The depth of this tree can be at most 64.
* `Mmr`: a Merkle mountain range structure designed to function as an append-only log.
* `PartialMerkleTree`: a partial view of a Merkle tree where some sub-trees may not be known. This is similar to a collection of Merkle paths all resolving to the same root. The length of the paths can be at most 64.
* `PartialMmr`: a partial view of a Merkle mountain range structure.
* `SimpleSmt`: a Sparse Merkle Tree (with no compaction), mapping 64-bit keys to 4-element values.
* `TieredSmt`: a Sparse Merkle tree (with compaction), mapping 4-element keys to 4-element values.

Expand Down
35 changes: 18 additions & 17 deletions benches/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ In the Miden VM, we make use of different hash functions. Some of these are "tra
* **Poseidon** as specified [here](https://eprint.iacr.org/2019/458.pdf) and implemented [here](https://github.com/mir-protocol/plonky2/blob/806b88d7d6e69a30dc0b4775f7ba275c45e8b63b/plonky2/src/hash/poseidon_goldilocks.rs) (but in pure Rust, without vectorized instructions).
* **Rescue Prime (RP)** as specified [here](https://eprint.iacr.org/2020/1143) and implemented [here](https://github.com/novifinancial/winterfell/blob/46dce1adf0/crypto/src/hash/rescue/rp64_256/mod.rs).
* **Rescue Prime Optimized (RPO)** as specified [here](https://eprint.iacr.org/2022/1577) and implemented in this crate.
* **Rescue Prime Extended (RPX)** a variant of the [xHash](https://eprint.iacr.org/2023/1045) hash function as implemented in this crate.

## Comparison and Instructions

Expand All @@ -15,28 +16,28 @@ The second scenario is that of sequential hashing where we take a sequence of le

#### Scenario 1: 2-to-1 hashing `h(a,b)`

| Function | BLAKE3 | SHA3 | Poseidon | Rp64_256 | RPO_256 |
| ------------------- | ------ | --------| --------- | --------- | ------- |
| Apple M1 Pro | 80 ns | 245 ns | 1.5 us | 9.1 us | 5.4 us |
| Apple M2 | 76 ns | 233 ns | 1.3 us | 7.9 us | 5.0 us |
| Amazon Graviton 3 | 108 ns | | | | 5.3 us |
| AMD Ryzen 9 5950X | 64 ns | 273 ns | 1.2 us | 9.1 us | 5.5 us |
| Intel Core i5-8279U | 80 ns | | | | 8.7 us |
| Intel Xeon 8375C | 67 ns | | | | 8.2 us |
| Function | BLAKE3 | SHA3 | Poseidon | Rp64_256 | RPO_256 | RPX_256 |
| ------------------- | ------ | ------- | --------- | --------- | ------- | ------- |
| Apple M1 Pro | 76 ns | 245 ns | 1.5 µs | 9.1 µs | 5.2 µs | 2.7 µs |
| Apple M2 Max | 71 ns | 233 ns | 1.3 µs | 7.9 µs | 4.6 µs | 2.4 µs |
| Amazon Graviton 3 | 108 ns | | | | 5.3 µs | 3.1 µs |
| AMD Ryzen 9 5950X | 64 ns | 273 ns | 1.2 µs | 9.1 µs | 5.5 µs | |
| Intel Core i5-8279U | 68 ns | 536 ns | 2.0 µs | 13.6 µs | 8.5 µs | 4.4 µs |
| Intel Xeon 8375C | 67 ns | | | | 8.2 µs | |

#### Scenario 2: Sequential hashing of 100 elements `h([a_0,...,a_99])`

| Function | BLAKE3 | SHA3 | Poseidon | Rp64_256 | RPO_256 |
| ------------------- | -------| ------- | --------- | --------- | ------- |
| Apple M1 Pro | 1.0 us | 1.5 us | 19.4 us | 118 us | 70 us |
| Apple M2 | 1.0 us | 1.5 us | 17.4 us | 103 us | 65 us |
| Amazon Graviton 3 | 1.4 us | | | | 69 us |
| AMD Ryzen 9 5950X | 0.8 us | 1.7 us | 15.7 us | 120 us | 72 us |
| Intel Core i5-8279U | 1.0 us | | | | 116 us |
| Intel Xeon 8375C | 0.8 ns | | | | 110 us |
| Function | BLAKE3 | SHA3 | Poseidon | Rp64_256 | RPO_256 | RPX_256 |
| ------------------- | -------| ------- | --------- | --------- | ------- | ------- |
| Apple M1 Pro | 1.0 µs | 1.5 µs | 19.4 µs | 118 µs | 69 µs | 35 µs |
| Apple M2 Max | 0.9 µs | 1.5 µs | 17.4 µs | 103 µs | 60 µs | 31 µs |
| Amazon Graviton 3 | 1.4 µs | | | | 69 µs | 41 µs |
| AMD Ryzen 9 5950X | 0.8 µs | 1.7 µs | 15.7 µs | 120 µs | 72 µs | |
| Intel Core i5-8279U | 0.9 µs | | | | 107 µs | 56 µs |
| Intel Xeon 8375C | 0.8 µs | | | | 110 µs | |

Notes:
- On Graviton 3, RPO256 is run with SVE acceleration enabled.
- On Graviton 3, RPO256 and RPX256 are run with SVE acceleration enabled.

### Instructions
Before you can run the benchmarks, you'll need to make sure you have Rust [installed](https://www.rust-lang.org/tools/install). After that, to run the benchmarks for RPO and BLAKE3, clone the current repository, and from the root directory of the repo run the following:
Expand Down
59 changes: 58 additions & 1 deletion benches/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use miden_crypto::{
hash::{
blake::Blake3_256,
rpo::{Rpo256, RpoDigest},
rpx::{Rpx256, RpxDigest},
},
Felt,
};
Expand Down Expand Up @@ -57,6 +58,54 @@ fn rpo256_sequential(c: &mut Criterion) {
});
}

fn rpx256_2to1(c: &mut Criterion) {
let v: [RpxDigest; 2] = [Rpx256::hash(&[1_u8]), Rpx256::hash(&[2_u8])];
c.bench_function("RPX256 2-to-1 hashing (cached)", |bench| {
bench.iter(|| Rpx256::merge(black_box(&v)))
});

c.bench_function("RPX256 2-to-1 hashing (random)", |bench| {
bench.iter_batched(
|| {
[
Rpx256::hash(&rand_value::<u64>().to_le_bytes()),
Rpx256::hash(&rand_value::<u64>().to_le_bytes()),
]
},
|state| Rpx256::merge(&state),
BatchSize::SmallInput,
)
});
}

fn rpx256_sequential(c: &mut Criterion) {
let v: [Felt; 100] = (0..100)
.into_iter()
.map(Felt::new)
.collect::<Vec<Felt>>()
.try_into()
.expect("should not fail");
c.bench_function("RPX256 sequential hashing (cached)", |bench| {
bench.iter(|| Rpx256::hash_elements(black_box(&v)))
});

c.bench_function("RPX256 sequential hashing (random)", |bench| {
bench.iter_batched(
|| {
let v: [Felt; 100] = (0..100)
.into_iter()
.map(|_| Felt::new(rand_value()))
.collect::<Vec<Felt>>()
.try_into()
.expect("should not fail");
v
},
|state| Rpx256::hash_elements(&state),
BatchSize::SmallInput,
)
});
}

fn blake3_2to1(c: &mut Criterion) {
let v: [<Blake3_256 as Hasher>::Digest; 2] =
[Blake3_256::hash(&[1_u8]), Blake3_256::hash(&[2_u8])];
Expand Down Expand Up @@ -106,5 +155,13 @@ fn blake3_sequential(c: &mut Criterion) {
});
}

criterion_group!(hash_group, rpo256_2to1, rpo256_sequential, blake3_2to1, blake3_sequential);
criterion_group!(
hash_group,
rpx256_2to1,
rpx256_sequential,
rpo256_2to1,
rpo256_sequential,
blake3_2to1,
blake3_sequential
);
criterion_main!(hash_group);
58 changes: 58 additions & 0 deletions src/dsa/rpo_falcon512/falcon_c/falcon.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ int PQCLEAN_FALCON512_CLEAN_crypto_sign_keypair_from_seed_rpo(
return 0;
}

/* see falcon.h */
int PQCLEAN_FALCON512_CLEAN_crypto_sign_keypair_rpo(
uint8_t *pk,
uint8_t *sk
Expand All @@ -126,6 +127,63 @@ int PQCLEAN_FALCON512_CLEAN_crypto_sign_keypair_rpo(
return PQCLEAN_FALCON512_CLEAN_crypto_sign_keypair_from_seed_rpo(pk, sk, seed);
}

/* see falcon.h */
int PQCLEAN_FALCON512_CLEAN_crypto_pk_from_sk_rpo(
const uint8_t *sk,
uint8_t *pk)
{
uint8_t b[FALCON_KEYGEN_TEMP_9];
int8_t f[512], g[512];
uint16_t h[512];
size_t u, v;

/*
* Decode the private key.
*/
if (sk[0] != 0x50 + 9)
{
return -1;
}
u = 1;
v = PQCLEAN_FALCON512_CLEAN_trim_i8_decode(
f, 9, PQCLEAN_FALCON512_CLEAN_max_fg_bits[9],
sk + u, PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES - u);
if (v == 0)
{
return -1;
}
u += v;
v = PQCLEAN_FALCON512_CLEAN_trim_i8_decode(
g, 9, PQCLEAN_FALCON512_CLEAN_max_fg_bits[9],
sk + u, PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES - u);
if (v == 0)
{
return -1;
}

/*
* Compute public key h = g.f^(-1) mod X^N+1 mod q.
*/
if (!PQCLEAN_FALCON512_CLEAN_compute_public(h, f, g, 9, (uint8_t *)b))
{
return -1;
}

/*
* Encode public key.
*/
pk[0] = 0x00 + 9;
v = PQCLEAN_FALCON512_CLEAN_modq_encode(
pk + 1, PQCLEAN_FALCON512_CLEAN_CRYPTO_PUBLICKEYBYTES - 1,
h, 9);
if (v != PQCLEAN_FALCON512_CLEAN_CRYPTO_PUBLICKEYBYTES - 1)
{
return -1;
}

return 0;
}

/*
* Compute the signature. nonce[] receives the nonce and must have length
* NONCELEN bytes. sigbuf[] receives the signature value (without nonce
Expand Down
7 changes: 7 additions & 0 deletions src/dsa/rpo_falcon512/falcon_c/falcon.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ int PQCLEAN_FALCON512_CLEAN_crypto_sign_keypair_rpo(
int PQCLEAN_FALCON512_CLEAN_crypto_sign_keypair_from_seed_rpo(
uint8_t *pk, uint8_t *sk, unsigned char *seed);

/*
* Generate the public key from the secret key (sk). Public key goes into pk[].
*
* Return value: 0 on success, -1 on error.
*/
int PQCLEAN_FALCON512_CLEAN_crypto_pk_from_sk_rpo(const uint8_t *sk, uint8_t *pk);

/*
* Compute a signature on a provided message (m, mlen), with a given
* private key (sk). Signature is written in sig[], with length written
Expand Down
13 changes: 11 additions & 2 deletions src/dsa/rpo_falcon512/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ extern "C" {
seed: *const u8,
) -> c_int;

/// Generates the public key from the private key. Public key goes into pk[].
///
/// Return value: 0 on success, -1 on error.
pub fn PQCLEAN_FALCON512_CLEAN_crypto_pk_from_sk_rpo(sk: *const u8, pk: *mut u8) -> c_int;

/// Compute a signature on a provided message (m, mlen), with a given private key (sk).
/// Signature is written in sig[], with length written into *siglen. Signature length is
/// variable; maximum signature length (in bytes) is 666.
Expand Down Expand Up @@ -103,11 +108,10 @@ mod tests {
#[test]
fn falcon_ffi() {
unsafe {
//let mut rng = rand::thread_rng();

// --- generate a key pair from a seed ----------------------------

let mut pk = [0u8; PK_LEN];
let mut pk_gen = [0u8; PK_LEN];
let mut sk = [0u8; SK_LEN];
let seed: [u8; NONCE_LEN] = rand_array();

Expand All @@ -120,6 +124,11 @@ mod tests {
)
);

// --- Generate public key from private key and check correctness -

PQCLEAN_FALCON512_CLEAN_crypto_pk_from_sk_rpo(sk.as_ptr(), pk_gen.as_mut_ptr());
assert_eq!(pk, pk_gen);

// --- sign a message and make sure it verifies -------------------

let mlen: usize = rand_value::<u16>() as usize;
Expand Down
Loading