Skip to content

Commit 6b8d597

Browse files
LLFournclaude
andcommitted
Remove type parameters from Message and Signature, and remove unused Slice type
"Secret messages" was a nice idea - it made it possible to have constant time verification of signatures so you didn't leak via side channel which signature you were verifying. But since almost no one has this peculiar requirement it created more friction than it was worth. This simplifies the API by: - Removing the secrecy type parameter from both Message and Signature types, making them always public - Removing the unused Slice type from secp256kfun which was part of the secrecy marking system but wasn't being used 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent d298d91 commit 6b8d597

File tree

15 files changed

+86
-228
lines changed

15 files changed

+86
-228
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
- **BREAKING**: Refactor `CompactProof` in `sigma_fun` to use two type parameters `CompactProof<R, L>` instead of `CompactProof<S: Sigma>` to enable serde support
99
- Add `Message::new` for BIP340-compliant domain separation using 33-byte padded prefix
1010
- Deprecate `Message::plain` which uses non-standard 64-byte prefix
11+
- Remove type parameters from `Message` and `Signature` types (always public now)
12+
- Remove unused `Slice` type from secp256kfun
1113

1214
## v0.11.0
1315

schnorr_fun/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ let schnorr = Schnorr::<Sha256, _>::new(nonce_gen.clone());
3939
// Generate your public/private key-pair
4040
let keypair = schnorr.new_keypair(Scalar::random(&mut rand::thread_rng()));
4141
// Sign a variable length message
42-
let message = Message::<Public>::plain("the-times-of-london", b"Chancellor on brink of second bailout for banks");
42+
let message = Message::new("the-times-of-london", b"Chancellor on brink of second bailout for banks");
4343
// Sign the message with our keypair
4444
let signature = schnorr.sign(&keypair, message);
4545
// Get the verifier's key

schnorr_fun/benches/bench_schnorr.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ fn sign_schnorr(c: &mut Criterion) {
2020
{
2121
let keypair = schnorr.new_keypair(*SK);
2222
group.bench_function("fun::schnorr_sign", |b| {
23-
b.iter(|| schnorr.sign(&keypair, Message::<Public>::raw(MESSAGE)))
23+
b.iter(|| schnorr.sign(&keypair, Message::raw(MESSAGE)))
2424
});
2525
}
2626

@@ -40,19 +40,14 @@ fn verify_schnorr(c: &mut Criterion) {
4040
let mut group = c.benchmark_group("schnorr_verify");
4141
let keypair = schnorr.new_keypair(*SK);
4242
{
43-
let message = Message::<Public>::raw(MESSAGE);
43+
let message = Message::raw(MESSAGE);
4444
let sig = schnorr.sign(&keypair, message);
4545
let verification_key = &keypair.public_key();
4646
group.bench_function("fun::schnorr_verify", |b| {
4747
b.iter(|| schnorr.verify(verification_key, message, &sig))
4848
});
4949

50-
{
51-
let sig = sig.set_secrecy::<Secret>();
52-
group.bench_function("fun::schnorr_verify_ct", |b| {
53-
b.iter(|| schnorr.verify(verification_key, message, &sig))
54-
});
55-
}
50+
// Constant-time verification is no longer supported after removing type parameters
5651
}
5752

5853
{

schnorr_fun/src/adaptor/encrypted_signature.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,8 @@ mod test {
4747
let schnorr = crate::new_with_deterministic_nonces::<sha2::Sha256>();
4848
let kp = schnorr.new_keypair(Scalar::random(&mut rand::thread_rng()));
4949
let encryption_key = Point::random(&mut rand::thread_rng());
50-
let encrypted_signature = schnorr.encrypted_sign(
51-
&kp,
52-
&encryption_key,
53-
Message::<Public>::plain("test", b"foo"),
54-
);
50+
let encrypted_signature =
51+
schnorr.encrypted_sign(&kp, &encryption_key, Message::new("test", b"foo"));
5552
let serialized = bincode::encode_to_vec(
5653
bincode::serde::Compat(&encrypted_signature),
5754
bincode::config::standard(),

schnorr_fun/src/adaptor/mod.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
//! let verification_key = signing_keypair.public_key();
2424
//! let decryption_key = Scalar::random(&mut rand::thread_rng());
2525
//! let encryption_key = schnorr.encryption_key_for(&decryption_key);
26-
//! let message = Message::<Public>::plain("text-bitcoin", b"send 1 BTC to Bob");
26+
//! let message = Message::new("text-bitcoin", b"send 1 BTC to Bob");
2727
//!
2828
//! // Alice knows: signing_keypair, encryption_key
2929
//! // Bob knows: decryption_key, verification_key
@@ -68,7 +68,7 @@ pub trait EncryptedSign {
6868
&self,
6969
signing_keypair: &KeyPair<EvenY>,
7070
encryption_key: &Point<Normal, impl Secrecy>,
71-
message: Message<'_, impl Secrecy>,
71+
message: Message<'_>,
7272
) -> EncryptedSignature;
7373
}
7474

@@ -81,7 +81,7 @@ where
8181
&self,
8282
signing_key: &KeyPair<EvenY>,
8383
encryption_key: &Point<Normal, impl Secrecy>,
84-
message: Message<'_, impl Secrecy>,
84+
message: Message<'_>,
8585
) -> EncryptedSignature {
8686
let (x, X) = signing_key.as_tuple();
8787
let Y = encryption_key;
@@ -139,7 +139,7 @@ pub trait Adaptor {
139139
&self,
140140
verification_key: &Point<EvenY, impl Secrecy>,
141141
encryption_key: &Point<impl PointType, impl Secrecy>,
142-
message: Message<'_, impl Secrecy>,
142+
message: Message<'_>,
143143
encrypted_signature: &EncryptedSignature<impl Secrecy>,
144144
) -> bool;
145145

@@ -179,7 +179,7 @@ pub trait Adaptor {
179179
&self,
180180
encryption_key: &Point<impl Normalized, impl Secrecy>,
181181
encrypted_signature: &EncryptedSignature<impl Secrecy>,
182-
signature: &Signature<impl Secrecy>,
182+
signature: &Signature,
183183
) -> Option<Scalar>;
184184
}
185185

@@ -195,7 +195,7 @@ where
195195
&self,
196196
verification_key: &Point<EvenY, impl Secrecy>,
197197
encryption_key: &Point<impl PointType, impl Secrecy>,
198-
message: Message<'_, impl Secrecy>,
198+
message: Message<'_>,
199199
encrypted_signature: &EncryptedSignature<impl Secrecy>,
200200
) -> bool {
201201
let EncryptedSignature {
@@ -236,7 +236,7 @@ where
236236
&self,
237237
encryption_key: &Point<impl PointType, impl Secrecy>,
238238
encrypted_signature: &EncryptedSignature<impl Secrecy>,
239-
signature: &Signature<impl Secrecy>,
239+
signature: &Signature,
240240
) -> Option<Scalar> {
241241
if signature.R != encrypted_signature.R {
242242
return None;
@@ -298,7 +298,7 @@ mod test {
298298
let signing_keypair = schnorr.new_keypair(secret_key);
299299
let verification_key = signing_keypair.public_key();
300300
let encryption_key = schnorr.encryption_key_for(&decryption_key);
301-
let message = Message::<Public>::new("test", b"give 100 coins to Bob".as_ref());
301+
let message = Message::new("test", b"give 100 coins to Bob".as_ref());
302302

303303
let encrypted_signature =
304304
schnorr.encrypted_sign(&signing_keypair, &encryption_key, message);

schnorr_fun/src/frost/chilldkg.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ pub mod simplepedpop {
101101
let secret_poly = poly::scalar::generate(threshold as usize, rng);
102102
let pop_keypair = KeyPair::new_xonly(secret_poly[0]);
103103
// XXX The thing that's singed differs from the spec
104-
let pop = schnorr.sign(&pop_keypair, Message::<Public>::empty());
104+
let pop = schnorr.sign(&pop_keypair, Message::empty());
105105
let com = poly::scalar::to_point_poly(&secret_poly);
106106

107107
let shares = share_receivers
@@ -201,7 +201,7 @@ pub mod simplepedpop {
201201
}
202202

203203
let (first_coeff_even_y, _) = input.com[0].into_point_with_even_y();
204-
if !schnorr.verify(&first_coeff_even_y, Message::<Public>::empty(), &input.pop) {
204+
if !schnorr.verify(&first_coeff_even_y, Message::empty(), &input.pop) {
205205
return Err("☠ pop didn't verify");
206206
}
207207
*entry = Some(input);
@@ -324,7 +324,7 @@ pub mod simplepedpop {
324324
{
325325
for (key_contrib, pop) in &agg_input.key_contrib {
326326
let (first_coeff_even_y, _) = key_contrib.into_point_with_even_y();
327-
if !schnorr.verify(&first_coeff_even_y, Message::<Public>::empty(), pop) {
327+
if !schnorr.verify(&first_coeff_even_y, Message::empty(), pop) {
328328
return Err(ReceiveShareError::InvalidPop);
329329
}
330330
}
@@ -606,7 +606,7 @@ pub mod encpedpop {
606606
{
607607
schnorr.sign(
608608
keypair,
609-
Message::<Public>::new("BIP DKG/cert", self.cert_bytes().as_ref()),
609+
Message::new("BIP DKG/cert", self.cert_bytes().as_ref()),
610610
)
611611
}
612612

@@ -620,7 +620,7 @@ pub mod encpedpop {
620620
) -> bool {
621621
schnorr.verify(
622622
&cert_key,
623-
Message::<Public>::new("BIP DKG/cert", self.cert_bytes().as_ref()),
623+
Message::new("BIP DKG/cert", self.cert_bytes().as_ref()),
624624
&signature,
625625
)
626626
}

schnorr_fun/src/frost/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
//! let xonly_shared_key = shared_key.into_xonly(); // this is the key signatures will be valid under
3131
//! let xonly_my_secret_share = my_secret_share.into_xonly();
3232
//! # let xonly_secret_share3 = secret_share3.into_xonly();
33-
//! let message = Message::plain("my-app", b"chancellor on brink of second bailout for banks");
33+
//! let message = Message::new("my-app", b"chancellor on brink of second bailout for banks");
3434
//! // Generate nonces for this signing session (and send them to coordinator somehow)
3535
//! // ⚠ session_id MUST be different for every signing attempt to avoid nonce reuse (if using deterministic nonces).
3636
//! let session_id = b"signing-ominous-message-about-banks-attempt-1".as_slice();
@@ -446,7 +446,7 @@ mod test {
446446
let session = frost.coordinator_sign_session(
447447
&frost_poly.into_xonly(),
448448
BTreeMap::from_iter([(s!(1).public(), nonce), (s!(2).public(), malicious_nonce)]),
449-
Message::<Public>::new("test", b"hello"),
449+
Message::new("test", b"hello"),
450450
);
451451

452452
assert_eq!(session.final_nonce(), *G);

schnorr_fun/src/message.rs

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
use secp256kfun::{
2-
Slice,
32
digest::{self},
43
hash::HashInto,
5-
marker::*,
64
};
75

86
/// A message to be signed.
9-
///
10-
/// The `S` parameter is a [`Secrecy`] which is used when signing a verifying to check whether the
11-
/// challenge scalar produced with the message should be secret.
127
#[derive(Debug, Clone, Copy, PartialEq)]
13-
pub struct Message<'a, S = Public> {
8+
pub struct Message<'a> {
149
/// The message bytes
15-
pub bytes: Slice<'a, S>,
10+
pub bytes: &'a [u8],
1611
/// The optional application tag to separate the signature from other applications.
1712
#[deprecated(
1813
since = "0.11.0",
@@ -24,12 +19,12 @@ pub struct Message<'a, S = Public> {
2419
}
2520

2621
#[allow(deprecated)]
27-
impl<'a, S: Secrecy> Message<'a, S> {
22+
impl<'a> Message<'a> {
2823
/// Create a raw message with no domain separation. The message bytes will be passed straight into the
2924
/// challenge hash. Usually, you only use this when signing a pre-hashed message.
3025
pub fn raw(bytes: &'a [u8]) -> Self {
3126
Message {
32-
bytes: Slice::from(bytes),
27+
bytes,
3328
app_tag: None,
3429
bip340_domain_sep: None,
3530
}
@@ -47,8 +42,8 @@ impl<'a, S: Secrecy> Message<'a, S> {
4742
///
4843
/// # Example
4944
/// ```
50-
/// use schnorr_fun::{Message, fun::marker::Public};
51-
/// let message = Message::<Public>::new("my-app/sign", b"hello world");
45+
/// use schnorr_fun::Message;
46+
/// let message = Message::new("my-app/sign", b"hello world");
5247
/// ```
5348
pub fn new(domain_sep: &'static str, bytes: &'a [u8]) -> Self {
5449
assert!(!domain_sep.is_empty(), "domain separator must not be empty");
@@ -57,7 +52,7 @@ impl<'a, S: Secrecy> Message<'a, S> {
5752
"domain separator must be 33 bytes or less"
5853
);
5954
Message {
60-
bytes: Slice::from(bytes),
55+
bytes,
6156
app_tag: None,
6257
bip340_domain_sep: Some(domain_sep),
6358
}
@@ -82,7 +77,7 @@ impl<'a, S: Secrecy> Message<'a, S> {
8277
assert!(app_tag.len() <= 64, "tag must be 64 bytes or less");
8378
assert!(!app_tag.is_empty(), "tag must not be empty");
8479
Message {
85-
bytes: Slice::from(bytes),
80+
bytes,
8681
app_tag: Some(app_tag),
8782
bip340_domain_sep: None,
8883
}
@@ -96,15 +91,15 @@ impl<'a, S: Secrecy> Message<'a, S> {
9691
/// Length of the message as it is hashed
9792
pub fn len(&self) -> usize {
9893
match (self.app_tag, self.bip340_domain_sep) {
99-
(Some(_), _) => 64 + self.bytes.as_inner().len(),
100-
(_, Some(_)) => 33 + self.bytes.as_inner().len(), // BIP340 style uses 33-byte prefix
101-
(None, None) => self.bytes.as_inner().len(),
94+
(Some(_), _) => 64 + self.bytes.len(),
95+
(_, Some(_)) => 33 + self.bytes.len(), // BIP340 style uses 33-byte prefix
96+
(None, None) => self.bytes.len(),
10297
}
10398
}
10499
}
105100

106101
#[allow(deprecated)]
107-
impl<S> HashInto for Message<'_, S> {
102+
impl HashInto for Message<'_> {
108103
fn hash_into(self, hash: &mut impl digest::Update) {
109104
if let Some(prefix) = self.app_tag {
110105
let mut padded_prefix = [0u8; 64];
@@ -116,7 +111,7 @@ impl<S> HashInto for Message<'_, S> {
116111
padded_prefix[..domain_sep.len()].copy_from_slice(domain_sep.as_bytes());
117112
hash.update(&padded_prefix);
118113
}
119-
hash.update(self.bytes.as_inner());
114+
hash.update(self.bytes);
120115
}
121116
}
122117

@@ -128,13 +123,13 @@ mod test {
128123
#[test]
129124
fn bip340_domain_separation() {
130125
// Test that BIP340 domain separation uses 33-byte prefix
131-
let msg = Message::<Public>::new("test", b"hello");
126+
let msg = Message::new("test", b"hello");
132127

133128
// Expected: "test" padded to 33 bytes + "hello"
134129
let mut expected_hash = Sha256::default();
135130
let mut padded_prefix = [0u8; 33];
136131
padded_prefix[..4].copy_from_slice(b"test");
137-
expected_hash.update(&padded_prefix);
132+
expected_hash.update(padded_prefix);
138133
expected_hash.update(b"hello");
139134

140135
let mut actual_hash = Sha256::default();
@@ -148,20 +143,20 @@ mod test {
148143

149144
#[test]
150145
fn message_new_fixed_key_signature() {
151-
use crate::{fun::s, new_with_deterministic_nonces};
146+
use crate::{Signature, fun::prelude::*, new_with_deterministic_nonces};
152147
use core::str::FromStr;
153148

154149
// Fixed test to ensure Message::new domain separation doesn't accidentally change
155150
let schnorr = new_with_deterministic_nonces::<Sha256>();
156151
let secret_key = s!(42);
157152
let keypair = schnorr.new_keypair(secret_key);
158153

159-
let message = Message::<Public>::new("test-app", b"test message");
154+
let message = Message::new("test-app", b"test message");
160155
let signature = schnorr.sign(&keypair, message);
161156

162157
// This signature was generated with the current implementation and should never change
163158
// to ensure backwards compatibility
164-
let expected_sig = crate::Signature::<Public>::from_str(
159+
let expected_sig = Signature::from_str(
165160
"5c49762df465f21993af631caedb3e478793142e15f200e70511e5af71387e52a3b9b6af189fa4b28a767254f2a8977f2e9db1866ad4dfbb083bb4fbd8dfe82e"
166161
).unwrap();
167162

schnorr_fun/src/musig.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
//! # let p3_public_nonce = p3_nonce.public();
3838
//! // collect the public nonces from the other two parties
3939
//! let nonces = vec![my_public_nonce, p2_public_nonce, p3_public_nonce];
40-
//! let message = Message::plain("my-app", b"chancellor on brink of second bailout for banks");
40+
//! let message = Message::new("my-app", b"chancellor on brink of second bailout for banks");
4141
//! // start the signing session
4242
//! let session = musig.start_sign_session(&agg_key, nonces, message);
4343
//! // sign with our single local keypair
@@ -444,7 +444,7 @@ impl<H: Hash32, NG> MuSig<H, NG> {
444444
&self,
445445
agg_key: &AggKey<EvenY>,
446446
nonces: Vec<binonce::Nonce>,
447-
message: Message<'_, Public>,
447+
message: Message<'_>,
448448
) -> SignSession {
449449
let (b, c, public_nonces, R, nonce_needs_negation) =
450450
self._start_sign_session(agg_key, nonces, message, Point::<Normal, Public, _>::zero());
@@ -482,7 +482,7 @@ impl<H: Hash32, NG> MuSig<H, NG> {
482482
&self,
483483
agg_key: &AggKey<EvenY>,
484484
nonces: Vec<binonce::Nonce>,
485-
message: Message<'_, Public>,
485+
message: Message<'_>,
486486
encryption_key: Point<impl PointType, impl Secrecy, impl ZeroChoice>,
487487
) -> Option<SignSession<Adaptor>> {
488488
let (b, c, public_nonces, R, nonce_needs_negation) =
@@ -504,7 +504,7 @@ impl<H: Hash32, NG> MuSig<H, NG> {
504504
&self,
505505
agg_key: &AggKey<EvenY>,
506506
mut nonces: Vec<binonce::Nonce>,
507-
message: Message<'_, Public>,
507+
message: Message<'_>,
508508
encryption_key: Point<impl PointType, impl Secrecy, impl ZeroChoice>,
509509
) -> (
510510
Scalar<Public>,
@@ -761,9 +761,9 @@ mod test {
761761
assert_eq!(agg_key1.agg_public_key(), agg_key3.agg_public_key());
762762

763763
let message =
764-
Message::<Public>::new("test", b"Chancellor on brink of second bailout for banks");
764+
Message::new("test", b"Chancellor on brink of second bailout for banks");
765765

766-
let session_id = message.bytes.into();
766+
let session_id = message.bytes;
767767

768768
let mut nonce_rng: ChaCha20Rng = musig.seed_nonce_rng(&agg_key1, keypair1.secret_key(), session_id);
769769
let p1_nonce = musig.gen_nonce(&mut nonce_rng);
@@ -856,9 +856,9 @@ mod test {
856856
]).into_xonly_key();
857857

858858
let message =
859-
Message::<Public>::new("test", b"Chancellor on brink of second bailout for banks");
859+
Message::new("test", b"Chancellor on brink of second bailout for banks");
860860

861-
let session_id = message.bytes.into();
861+
let session_id = message.bytes;
862862

863863
let mut nonce_rng: ChaCha20Rng = musig.seed_nonce_rng(&agg_key1, keypair1.secret_key(), session_id);
864864
let p1_nonce = musig.gen_nonce(&mut nonce_rng);

0 commit comments

Comments
 (0)