Skip to content

Commit ca7cbd9

Browse files
authored
Merge pull request #2545 from input-output-hk/curiecrypt/module-single-signature
Organize STM - Module Single Signature
2 parents c79b85c + 56e3ab5 commit ca7cbd9

File tree

7 files changed

+244
-205
lines changed

7 files changed

+244
-205
lines changed

mithril-stm/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## 0.4.1 (04-06-2025)
9+
10+
### Added
11+
12+
- Added a `single_signature` module and `StmSig` and `StmSigRegParty` functionality covered by its submodules.
13+
814
## 0.4.0 (15-05-2025)
915

1016
### Added

mithril-stm/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod error;
77
mod key_reg;
88
mod merkle_tree;
99
mod participant;
10+
mod single_signature;
1011
mod stm;
1112

1213
pub use error::{
@@ -15,9 +16,9 @@ pub use error::{
1516
};
1617
pub use key_reg::{ClosedKeyReg, KeyReg};
1718
pub use participant::{StmInitializer, StmSigner, StmVerificationKey, StmVerificationKeyPoP};
19+
pub use single_signature::{StmSig, StmSigRegParty};
1820
pub use stm::{
1921
CoreVerifier, Index, Stake, StmAggrSig, StmAggrVerificationKey, StmClerk, StmParameters,
20-
StmSig, StmSigRegParty,
2122
};
2223

2324
#[cfg(feature = "benchmark-internals")]

mithril-stm/src/participant/signer.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
use blake2::digest::{Digest, FixedOutput};
2+
13
use crate::bls_multi_signature::{Signature, SigningKey, VerificationKey};
24
use crate::eligibility_check::ev_lt_phi;
35
use crate::key_reg::ClosedKeyReg;
4-
use crate::stm::{Stake, StmParameters, StmSig};
5-
use blake2::digest::{Digest, FixedOutput};
6+
use crate::single_signature::StmSig;
7+
use crate::stm::{Stake, StmParameters};
68

79
/// Wrapper of the MultiSignature Verification key
810
pub type StmVerificationKey = VerificationKey;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
mod signature;
2+
mod signature_registered_party;
3+
4+
pub use signature::*;
5+
pub use signature_registered_party::*;
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
use std::cmp::Ordering;
2+
use std::hash::{Hash, Hasher};
3+
4+
use blake2::digest::{Digest, FixedOutput};
5+
use serde::{Deserialize, Serialize};
6+
7+
use crate::bls_multi_signature::Signature;
8+
use crate::eligibility_check::ev_lt_phi;
9+
use crate::{
10+
Index, Stake, StmAggrVerificationKey, StmParameters, StmSignatureError, StmVerificationKey,
11+
};
12+
13+
/// Signature created by a single party who has won the lottery.
14+
#[derive(Debug, Clone, Serialize, Deserialize)]
15+
pub struct StmSig {
16+
/// The signature from the underlying MSP scheme.
17+
pub sigma: Signature,
18+
/// The index(es) for which the signature is valid
19+
pub indexes: Vec<Index>,
20+
/// Merkle tree index of the signer.
21+
pub signer_index: Index,
22+
}
23+
24+
impl StmSig {
25+
/// Verify an stm signature by checking that the lottery was won, the merkle path is correct,
26+
/// the indexes are in the desired range and the underlying multi signature validates.
27+
pub fn verify<D: Clone + Digest + FixedOutput>(
28+
&self,
29+
params: &StmParameters,
30+
pk: &StmVerificationKey,
31+
stake: &Stake,
32+
avk: &StmAggrVerificationKey<D>,
33+
msg: &[u8],
34+
) -> Result<(), StmSignatureError> {
35+
let msgp = avk.get_mt_commitment().concat_with_msg(msg);
36+
self.verify_core(params, pk, stake, &msgp, &avk.get_total_stake())?;
37+
Ok(())
38+
}
39+
40+
/// Verify that all indices of a signature are valid.
41+
pub(crate) fn check_indices(
42+
&self,
43+
params: &StmParameters,
44+
stake: &Stake,
45+
msg: &[u8],
46+
total_stake: &Stake,
47+
) -> Result<(), StmSignatureError> {
48+
for &index in &self.indexes {
49+
if index > params.m {
50+
return Err(StmSignatureError::IndexBoundFailed(index, params.m));
51+
}
52+
53+
let ev = self.sigma.eval(msg, index);
54+
55+
if !ev_lt_phi(params.phi_f, ev, *stake, *total_stake) {
56+
return Err(StmSignatureError::LotteryLost);
57+
}
58+
}
59+
60+
Ok(())
61+
}
62+
63+
/// Convert an `StmSig` into bytes
64+
///
65+
/// # Layout
66+
/// * Stake
67+
/// * Number of valid indexes (as u64)
68+
/// * Indexes of the signature
69+
/// * Public Key
70+
/// * Signature
71+
/// * Merkle index of the signer.
72+
pub fn to_bytes(&self) -> Vec<u8> {
73+
let mut output = Vec::new();
74+
output.extend_from_slice(&(self.indexes.len() as u64).to_be_bytes());
75+
76+
for index in &self.indexes {
77+
output.extend_from_slice(&index.to_be_bytes());
78+
}
79+
80+
output.extend_from_slice(&self.sigma.to_bytes());
81+
82+
output.extend_from_slice(&self.signer_index.to_be_bytes());
83+
output
84+
}
85+
86+
/// Extract a batch compatible `StmSig` from a byte slice.
87+
pub fn from_bytes<D: Clone + Digest + FixedOutput>(
88+
bytes: &[u8],
89+
) -> Result<StmSig, StmSignatureError> {
90+
let mut u64_bytes = [0u8; 8];
91+
92+
u64_bytes.copy_from_slice(&bytes[0..8]);
93+
let nr_indexes = u64::from_be_bytes(u64_bytes) as usize;
94+
95+
let mut indexes = Vec::new();
96+
for i in 0..nr_indexes {
97+
u64_bytes.copy_from_slice(&bytes[8 + i * 8..16 + i * 8]);
98+
indexes.push(u64::from_be_bytes(u64_bytes));
99+
}
100+
101+
let offset = 8 + nr_indexes * 8;
102+
let sigma = Signature::from_bytes(&bytes[offset..offset + 48])?;
103+
104+
u64_bytes.copy_from_slice(&bytes[offset + 48..offset + 56]);
105+
let signer_index = u64::from_be_bytes(u64_bytes);
106+
107+
Ok(StmSig {
108+
sigma,
109+
indexes,
110+
signer_index,
111+
})
112+
}
113+
114+
/// Compare two `StmSig` by their signers' merkle tree indexes.
115+
pub fn cmp_stm_sig(&self, other: &Self) -> Ordering {
116+
self.signer_index.cmp(&other.signer_index)
117+
}
118+
119+
/// Verify a core signature by checking that the lottery was won,
120+
/// the indexes are in the desired range and the underlying multi signature validates.
121+
pub fn verify_core(
122+
&self,
123+
params: &StmParameters,
124+
pk: &StmVerificationKey,
125+
stake: &Stake,
126+
msg: &[u8],
127+
total_stake: &Stake,
128+
) -> Result<(), StmSignatureError> {
129+
self.sigma.verify(msg, pk)?;
130+
self.check_indices(params, stake, msg, total_stake)?;
131+
132+
Ok(())
133+
}
134+
}
135+
136+
impl Hash for StmSig {
137+
fn hash<H: Hasher>(&self, state: &mut H) {
138+
Hash::hash_slice(&self.sigma.to_bytes(), state)
139+
}
140+
}
141+
142+
impl PartialEq for StmSig {
143+
fn eq(&self, other: &Self) -> bool {
144+
self.sigma == other.sigma
145+
}
146+
}
147+
148+
impl Eq for StmSig {}
149+
150+
impl PartialOrd for StmSig {
151+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
152+
Some(std::cmp::Ord::cmp(self, other))
153+
}
154+
}
155+
156+
impl Ord for StmSig {
157+
fn cmp(&self, other: &Self) -> Ordering {
158+
self.cmp_stm_sig(other)
159+
}
160+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use blake2::digest::{Digest, FixedOutput};
2+
use serde::ser::SerializeTuple;
3+
use serde::{Deserialize, Serialize, Serializer};
4+
5+
use crate::key_reg::RegParty;
6+
use crate::{StmSig, StmSignatureError};
7+
8+
/// Signature with its registered party.
9+
#[derive(Debug, Clone, Hash, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
10+
pub struct StmSigRegParty {
11+
/// Stm signature
12+
pub sig: StmSig,
13+
/// Registered party
14+
pub reg_party: RegParty,
15+
}
16+
17+
impl StmSigRegParty {
18+
/// Convert StmSigRegParty to bytes
19+
/// # Layout
20+
/// * RegParty
21+
/// * Signature
22+
pub fn to_bytes(&self) -> Vec<u8> {
23+
let mut out = Vec::new();
24+
out.extend_from_slice(&self.reg_party.to_bytes());
25+
out.extend_from_slice(&self.sig.to_bytes());
26+
27+
out
28+
}
29+
///Extract a `StmSigRegParty` from a byte slice.
30+
pub fn from_bytes<D: Digest + Clone + FixedOutput>(
31+
bytes: &[u8],
32+
) -> Result<StmSigRegParty, StmSignatureError> {
33+
let reg_party = RegParty::from_bytes(&bytes[0..104])?;
34+
let sig = StmSig::from_bytes::<D>(&bytes[104..])?;
35+
36+
Ok(StmSigRegParty { sig, reg_party })
37+
}
38+
}
39+
40+
impl Serialize for StmSigRegParty {
41+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
42+
where
43+
S: Serializer,
44+
{
45+
let mut tuple = serializer.serialize_tuple(2)?;
46+
tuple.serialize_element(&self.sig)?;
47+
tuple.serialize_element(&self.reg_party)?;
48+
tuple.end()
49+
}
50+
}

0 commit comments

Comments
 (0)