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

Derandomize RPO-STARK DSA #358

Merged
merged 4 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- [BREAKING] Updated Winterfell dependency to v0.11 (#346).
- Added RPO-STARK based DSA (#349).
- Added benchmarks for DSA implementations (#354).
- Implemented deterministic RPO-STARK based DSA (#358).

## 0.12.0 (2024-10-30)

Expand Down
47 changes: 38 additions & 9 deletions src/dsa/rpo_stark/stark/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use alloc::vec::Vec;
use core::marker::PhantomData;

use prover::RpoSignatureProver;
use rand::{distributions::Standard, prelude::Distribution, thread_rng, RngCore, SeedableRng};
use rand_chacha::ChaCha20Rng;
use winter_crypto::{ElementHasher, Hasher, SaltedMerkleTree};
use winter_crypto::{ElementHasher, SaltedMerkleTree};
use winter_math::fields::f64::BaseElement;
use winter_prover::{Proof, ProofOptions, Prover};
use winter_utils::Serializable;
use winter_verifier::{verify, AcceptableOptions, VerifierError};

use crate::{
Expand All @@ -24,10 +25,7 @@ pub struct RpoSignatureScheme<H: ElementHasher> {
_h: PhantomData<H>,
}

impl<H: ElementHasher<BaseField = BaseElement> + Sync> RpoSignatureScheme<H>
where
Standard: Distribution<<H as Hasher>::Digest>,
{
impl<H: ElementHasher<BaseField = BaseElement> + Sync> RpoSignatureScheme<H> {
pub fn new(options: ProofOptions) -> Self {
RpoSignatureScheme { options, _h: PhantomData }
}
Expand All @@ -40,9 +38,7 @@ where
let trace = prover.build_trace(sk);

// generate the initial seed for the PRNG used for zero-knowledge
let mut seed = <ChaCha20Rng as SeedableRng>::Seed::default();
let mut rng = thread_rng();
rng.fill_bytes(&mut seed);
let seed: [u8; 32] = generate_seed(sk, msg);

// generate the proof
prover.prove(trace, Some(seed)).expect("failed to generate the signature")
Expand All @@ -67,3 +63,36 @@ where
)
}
}

/// Deterministically generates a seed for seeding the PRNG used for zero-knowledge.
///
/// This uses the argument described in [RFC 6979](https://datatracker.ietf.org/doc/html/rfc6979#section-3.5)
/// § 3.5 where the concatenation of the private key and the hashed message, i.e., sk || H(m), is
/// used in order to construct the initial seed of a PRNG.
///
/// Note that we hash in also a context string in order to domain separate between different
/// instantiations of the signature scheme.
#[inline]
pub fn generate_seed(sk: [BaseElement; DIGEST_SIZE], msg: [BaseElement; DIGEST_SIZE]) -> [u8; 32] {
let context_bytes = "
Seed for PRNG used for Zero-knowledge in RPO-STARK signature scheme:
1. Version: Conjectured security
2. FRI queries: 30
3. Blowup factor: 8
4. Grinding bits: 12
5. Field extension degree: 2
6. FRI folding factor: 4
7. FRI remainder polynomial max degree: 7
"
.to_bytes();
let sk_bytes = sk.to_bytes();
let msg_bytes = msg.to_bytes();

let total_length = context_bytes.len() + sk_bytes.len() + msg_bytes.len();
let mut buffer = Vec::with_capacity(total_length);
buffer.extend_from_slice(&context_bytes);
buffer.extend_from_slice(&sk_bytes);
buffer.extend_from_slice(&msg_bytes);

blake3::hash(&buffer).into()
}
Loading