Skip to content
Open
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
6 changes: 6 additions & 0 deletions mithril-stm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 0.6.3 (12-03-2025)

### Added

- Jubjub wrapper added to schnorr signature module.

## 0.6.2 (11-27-2025)

### Changed
Expand Down
4 changes: 2 additions & 2 deletions mithril-stm/benches/schnorr_sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ fn sign_and_verify(c: &mut Criterion, nr_sigs: usize) {
let mut msks = Vec::new();
let mut sigs = Vec::new();
for _ in 0..nr_sigs {
let sk = SchnorrSigningKey::try_generate(&mut rng).unwrap();
let vk = SchnorrVerificationKey::from(&sk);
let sk = SchnorrSigningKey::generate(&mut rng).unwrap();
let vk = SchnorrVerificationKey::new_from_signing_key(sk.clone()).unwrap();
let sig = sk.sign(&msg, &mut rng_sig).unwrap();
sigs.push(sig);
mvks.push(vk);
Expand Down
3 changes: 1 addition & 2 deletions mithril-stm/src/membership_commitment/merkle_tree/leaf.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::cmp::Ordering;

use serde::{Deserialize, Serialize};
use std::cmp::Ordering;

use crate::{
MerkleTreeError, Stake, StmResult, VerificationKey, signature_scheme::BlsVerificationKey,
Expand Down
3 changes: 1 addition & 2 deletions mithril-stm/src/membership_commitment/merkle_tree/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,8 @@ mod tests {
use proptest::{collection::vec, prelude::*};
use rand::{rng, seq::IteratorRandom};

use crate::signature_scheme::BlsVerificationKey;

use super::*;
use crate::signature_scheme::BlsVerificationKey;

fn pow2_plus1(h: usize) -> usize {
1 + 2_usize.pow(h as u32)
Expand Down
3 changes: 1 addition & 2 deletions mithril-stm/src/protocol/aggregate_signature/signature.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::{collections::HashMap, fmt::Display, hash::Hash, str::FromStr};

use anyhow::anyhow;
use blake2::digest::{Digest, FixedOutput};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fmt::Display, hash::Hash, str::FromStr};

use super::AggregateVerificationKey;
use crate::{
Expand Down
8 changes: 3 additions & 5 deletions mithril-stm/src/protocol/key_registration.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
//! Key registration functionality.
use anyhow::anyhow;
use blake2::digest::{Digest, FixedOutput};
use std::{
collections::{HashMap, hash_map::Entry},
sync::Arc,
};

use anyhow::anyhow;
use blake2::digest::{Digest, FixedOutput};

use crate::{
RegisterError, Stake, StmResult,
membership_commitment::{MerkleTree, MerkleTreeLeaf},
Expand Down Expand Up @@ -95,9 +94,8 @@ mod tests {
use rand_chacha::ChaCha20Rng;
use rand_core::SeedableRng;

use crate::signature_scheme::BlsSigningKey;

use super::*;
use crate::signature_scheme::BlsSigningKey;

proptest! {
#[test]
Expand Down
7 changes: 3 additions & 4 deletions mithril-stm/src/protocol/single_signature/signature.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use anyhow::{Context, anyhow};
use blake2::digest::{Digest, FixedOutput};
use serde::{Deserialize, Serialize};
use std::{
cmp::Ordering,
hash::{Hash, Hasher},
};

use anyhow::{Context, anyhow};
use blake2::digest::{Digest, FixedOutput};
use serde::{Deserialize, Serialize};

use crate::{
AggregateVerificationKey, Index, Parameters, SignatureError, Stake, StmResult, VerificationKey,
is_lottery_won, signature_scheme::BlsSignature,
Expand Down
3 changes: 1 addition & 2 deletions mithril-stm/src/signature_scheme/bls_multi_signature/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,8 @@ mod tests {
use rand_core::{RngCore, SeedableRng};

use super::helper::unsafe_helpers::{p1_affine_to_sig, p2_affine_to_vk};
use crate::{KeyRegistration, MultiSignatureError, RegisterError};

use super::*;
use crate::{KeyRegistration, MultiSignatureError, RegisterError};

impl PartialEq for BlsSigningKey {
fn eq(&self, other: &Self) -> bool {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use anyhow::anyhow;
use blst::{
BLST_ERROR,
min_sig::{AggregatePublicKey, PublicKey as BlstVk},
};
use serde::{Deserialize, Serialize};
use std::{
cmp::Ordering,
fmt::{Display, Formatter},
hash::{Hash, Hasher},
iter::Sum,
};

use blst::{
BLST_ERROR,
min_sig::{AggregatePublicKey, PublicKey as BlstVk},
};
use serde::{Deserialize, Serialize};

use super::{BlsProofOfPossession, BlsSigningKey, POP, helper::unsafe_helpers::verify_pairing};
use crate::{MultiSignatureError, StmResult, blst_error_to_stm_error};

Expand Down
32 changes: 24 additions & 8 deletions mithril-stm/src/signature_scheme/schnorr_signature/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#[cfg(feature = "future_snark")]
use super::{SchnorrSignature, SchnorrVerificationKey};
use super::{PrimeOrderProjectivePoint, SchnorrSignature};

/// Error types for Schnorr signatures.
#[cfg(feature = "future_snark")]
Expand All @@ -9,19 +9,35 @@ pub enum SchnorrSignatureError {
#[error("Invalid Schnorr single signature")]
SignatureInvalid(Box<SchnorrSignature>),

/// Invalid Verification key
#[error("Invalid Schnorr Verification key")]
VerificationKeyInvalid(Box<SchnorrVerificationKey>),

/// This error occurs when the serialization of the raw bytes failed
#[error("Invalid bytes")]
SerializationError,

/// This error occurs when the signing key fails to generate
#[error("Failed generation of the signing key")]
SigningKeyGenerationError,
/// This error occurs when the serialization of the signing key bytes failed
#[error("Invalid scalar field element bytes")]
ScalarFieldElementSerializationError,

/// This error occurs when the serialization of the projective point bytes failed
#[error("Invalid projective point bytes")]
ProjectivePointSerializationError,

/// This error occurs when the serialization of the prime order projective point bytes failed
#[error("Invalid prime order projective point bytes")]
PrimeOrderProjectivePointSerializationError,

/// This error occurs when the random scalar fails to generate during the signature
#[error("Failed generation of the signature's random scalar")]
RandomScalarGenerationError,

/// This error occurs when signing key is zero or one.
#[error("The signing key is invalid.")]
InvalidSigningKey,

/// Given point is not on the curve
#[error("Given point is not on the curve")]
PointIsNotOnCurve(Box<PrimeOrderProjectivePoint>),

/// Given point is not prime order
#[error("Given point is not prime order")]
PointIsNotPrimeOrder(Box<PrimeOrderProjectivePoint>),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
use anyhow::anyhow;
use dusk_jubjub::{
AffinePoint as JubjubAffinePoint, EDWARDS_D, ExtendedPoint as JubjubExtended,
SubgroupPoint as JubjubSubgroup,
};
use group::{Group, GroupEncoding};

use super::{BaseFieldElement, ScalarFieldElement};
use crate::{StmResult, signature_scheme::SchnorrSignatureError};

#[derive(Clone)]
pub(crate) struct AffinePoint(JubjubAffinePoint);

impl AffinePoint {
pub(crate) fn from_projective_point(projective_point: ProjectivePoint) -> Self {
AffinePoint(JubjubAffinePoint::from(projective_point.0))
}

pub(crate) fn from_prime_order_projective_point(
prime_order_projective_point: &PrimeOrderProjectivePoint,
) -> Self {
AffinePoint(JubjubAffinePoint::from(
ProjectivePoint::from_prime_order_projective_point(*prime_order_projective_point).0,
))
}

pub(crate) fn get_u(&self) -> BaseFieldElement {
BaseFieldElement(self.0.get_u())
}

pub(crate) fn get_v(&self) -> BaseFieldElement {
BaseFieldElement(self.0.get_v())
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct ProjectivePoint(pub(crate) JubjubExtended);

impl ProjectivePoint {
pub(crate) fn hash_to_projective_point(input: &[u8]) -> Self {
ProjectivePoint(JubjubExtended::hash_to_point(input))
}

pub(crate) fn add(&self, other: Self) -> Self {
ProjectivePoint(self.0 + other.0)
}

pub(crate) fn scalar_multiplication(&self, scalar: &ScalarFieldElement) -> Self {
ProjectivePoint(self.0 * scalar.0)
}

pub(crate) fn get_coordinates(&self) -> (BaseFieldElement, BaseFieldElement) {
let affine_point = AffinePoint::from_projective_point(*self);

(affine_point.get_u(), affine_point.get_v())
}

pub(crate) fn to_bytes(self) -> [u8; 32] {
self.0.to_bytes()
}

pub(crate) fn from_bytes(bytes: &[u8]) -> StmResult<Self> {
let mut projective_point_bytes = [0u8; 32];
projective_point_bytes
.copy_from_slice(bytes.get(..32).ok_or(SchnorrSignatureError::SerializationError)?);

match JubjubExtended::from_bytes(&projective_point_bytes).into_option() {
Some(projective_point) => Ok(Self(projective_point)),
None => Err(anyhow!(
SchnorrSignatureError::ProjectivePointSerializationError
)),
}
}

pub(crate) fn from_prime_order_projective_point(
prime_order_projective_point: PrimeOrderProjectivePoint,
) -> Self {
ProjectivePoint(JubjubExtended::from(prime_order_projective_point.0))
}

pub(crate) fn is_prime_order(self) -> bool {
self.0.is_prime_order().into()
}
}

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub(crate) struct PrimeOrderProjectivePoint(pub(crate) JubjubSubgroup);

impl PrimeOrderProjectivePoint {
pub(crate) fn create_generator() -> Self {
PrimeOrderProjectivePoint(JubjubSubgroup::generator())
}

pub(crate) fn add(&self, other: Self) -> Self {
PrimeOrderProjectivePoint(self.0 + other.0)
}

pub(crate) fn scalar_multiplication(&self, scalar: &ScalarFieldElement) -> Self {
PrimeOrderProjectivePoint(self.0 * scalar.0)
}

/// Check if the given point is on the curve using its coordinates
pub(crate) fn is_on_curve(&self) -> StmResult<PrimeOrderProjectivePoint> {
let point_affine_representation = AffinePoint::from_prime_order_projective_point(self);
let (x, y) = (
point_affine_representation.get_u(),
point_affine_representation.get_v(),
);
let x_square = x.square();
let y_square = y.square();

let lhs = y_square.sub(&x_square);
let mut rhs = x_square.mul(&y_square);
rhs = rhs.mul(&BaseFieldElement(EDWARDS_D));
rhs = rhs.add(&BaseFieldElement::get_one());

if lhs != rhs {
return Err(anyhow!(SchnorrSignatureError::PointIsNotOnCurve(Box::new(
*self
))));
}
Ok(*self)
}

pub(crate) fn to_bytes(self) -> [u8; 32] {
self.0.to_bytes()
}

pub(crate) fn from_bytes(bytes: &[u8]) -> StmResult<Self> {
let mut prime_order_projective_point_bytes = [0u8; 32];
prime_order_projective_point_bytes
.copy_from_slice(bytes.get(..32).ok_or(SchnorrSignatureError::SerializationError)?);

match JubjubSubgroup::from_bytes(&prime_order_projective_point_bytes).into_option() {
Some(prime_order_projective_point) => Ok(Self(prime_order_projective_point)),
None => Err(anyhow!(
SchnorrSignatureError::PrimeOrderProjectivePointSerializationError
)),
}
}
}

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

mod golden {
use rand_chacha::ChaCha20Rng;
use rand_core::SeedableRng;

use super::*;

const GOLDEN_JSON: &str = r#"[144, 52, 95, 161, 127, 253, 49, 32, 140, 217, 231, 207, 32, 238, 244, 196, 97, 241, 47, 95, 101, 9, 70, 136, 194, 66, 187, 253, 200, 32, 218, 43]"#;

fn golden_value() -> PrimeOrderProjectivePoint {
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
let scalar = ScalarFieldElement::new_random_nonzero_scalar(&mut rng).unwrap();
let point = PrimeOrderProjectivePoint::create_generator();
point.scalar_multiplication(&scalar)
}

#[test]
fn golden_conversions() {
let value = serde_json::from_str(GOLDEN_JSON)
.expect("This JSON deserialization should not fail");
assert_eq!(golden_value(), value);

let serialized =
serde_json::to_string(&value).expect("This JSON serialization should not fail");
let golden_serialized = serde_json::to_string(&golden_value())
.expect("This JSON serialization should not fail");
assert_eq!(golden_serialized, serialized);
}
}
}
Loading
Loading