Skip to content

Commit 0ef8787

Browse files
jclapisltitanbManuelBilbao
authored
Add nonce and chain ID to signature requests (#354)
Co-authored-by: eltitanb <[email protected]> Co-authored-by: ltitanb <[email protected]> Co-authored-by: Manuel Iñaki Bilbao <[email protected]>
1 parent af13089 commit 0ef8787

File tree

16 files changed

+314
-106
lines changed

16 files changed

+314
-106
lines changed

api/signer-api.yml

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ paths:
7979
object_root:
8080
description: The 32-byte data you want to sign, with optional `0x` prefix.
8181
$ref: "#/components/schemas/B256"
82+
nonce:
83+
$ref: "#/components/schemas/Nonce"
8284
example:
8385
pubkey: "0xa3ffa9241f78279f1af04644cb8c79c2d8f02bcf0e28e2f186f6dcccac0a869c2be441fda50f0dea895cfce2e53f0989"
8486
object_root: "0x3e9f4a78b5c21d64f0b8e3d9a7f5c02b4d1e67a3c8f29b5d6e4a3b1c8f72e6d9"
@@ -217,6 +219,8 @@ paths:
217219
object_root:
218220
description: The 32-byte data you want to sign, with optional `0x` prefix.
219221
$ref: "#/components/schemas/B256"
222+
nonce:
223+
$ref: "#/components/schemas/Nonce"
220224
example:
221225
pubkey: "0xa3ffa9241f78279f1af04644cb8c79c2d8f02bcf0e28e2f186f6dcccac0a869c2be441fda50f0dea895cfce2e53f0989"
222226
object_root: "0x3e9f4a78b5c21d64f0b8e3d9a7f5c02b4d1e67a3c8f29b5d6e4a3b1c8f72e6d9"
@@ -355,6 +359,8 @@ paths:
355359
object_root:
356360
description: The 32-byte data you want to sign, with optional `0x` prefix.
357361
$ref: "#/components/schemas/B256"
362+
nonce:
363+
$ref: "#/components/schemas/Nonce"
358364
example:
359365
proxy: "0x71f65e9f6336770e22d148bd5e89b391a1c3b0bb"
360366
object_root: "0x3e9f4a78b5c21d64f0b8e3d9a7f5c02b4d1e67a3c8f29b5d6e4a3b1c8f72e6d9"
@@ -629,9 +635,15 @@ components:
629635
object_root:
630636
description: The 32-byte data that was signed, with `0x` prefix
631637
$ref: "#/components/schemas/B256"
632-
signing_id:
638+
module_signing_id:
633639
description: The signing ID of the module that requested the signature, as specified in the Commit-Boost configuration
634640
$ref: "#/components/schemas/B256"
641+
nonce:
642+
$ref: "#/components/schemas/Nonce"
643+
chain_id:
644+
description: The chain ID that the signature is valid for, as specified in the Commit-Boost configuration
645+
type: integer
646+
example: 1
635647
signature:
636648
description: The BLS signature of the Merkle root hash of the provided `object_root` field and the requesting module's Signing ID. For details on this signature, see the [signature structure documentation](https://commit-boost.github.io/commit-boost-client/developing/prop-commit-signing.md#structure-of-a-signature).
637649
$ref: "#/components/schemas/BlsSignature"
@@ -647,6 +659,18 @@ components:
647659
module_signing_id:
648660
description: The signing ID of the module that requested the signature, as specified in the Commit-Boost configuration
649661
$ref: "#/components/schemas/B256"
662+
nonce:
663+
$ref: "#/components/schemas/Nonce"
664+
chain_id:
665+
description: The chain ID that the signature is valid for, as specified in the Commit-Boost configuration
666+
type: integer
667+
example: 1
650668
signature:
651669
description: The ECDSA signature (in Ethereum RSV format) of the Merkle root hash of the provided `object_root` field and the requesting module's Signing ID. For details on this signature, see the [signature structure documentation](https://commit-boost.github.io/commit-boost-client/developing/prop-commit-signing.md#structure-of-a-signature).
652-
$ref: "#/components/schemas/EcdsaSignature"
670+
$ref: "#/components/schemas/EcdsaSignature"
671+
Nonce:
672+
type: integer
673+
description: If your module tracks nonces per signature (e.g., to prevent replay attacks), this is the unique nonce to use for the signature. It should be an unsigned 64-bit integer in big-endian format. It must be between 0 and 2^64-2, inclusive. If your module doesn't use nonces, we suggest setting this to 2^64-1 instead of 0 because 0 is a legal nonce and will cause complications with your module if you ever want to use a nonce in the future.
674+
minimum: 0
675+
maximum: 18446744073709551614 // 2^64-2
676+
example: 1

crates/common/src/commit/request.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,16 @@ impl<T: ProxyId> fmt::Display for SignedProxyDelegation<T> {
7777
pub struct SignConsensusRequest {
7878
pub pubkey: BlsPublicKey,
7979
pub object_root: B256,
80+
pub nonce: u64,
8081
}
8182

8283
impl SignConsensusRequest {
83-
pub fn new(pubkey: BlsPublicKey, object_root: B256) -> Self {
84-
Self { pubkey, object_root }
84+
pub fn new(pubkey: BlsPublicKey, object_root: B256, nonce: u64) -> Self {
85+
Self { pubkey, object_root, nonce }
8586
}
8687

8788
pub fn builder(pubkey: BlsPublicKey) -> Self {
88-
Self::new(pubkey, B256::ZERO)
89+
Self::new(pubkey, B256::ZERO, u64::MAX - 1)
8990
}
9091

9192
pub fn with_root<R: Into<B256>>(self, object_root: R) -> Self {
@@ -95,15 +96,20 @@ impl SignConsensusRequest {
9596
pub fn with_msg(self, msg: &impl TreeHash) -> Self {
9697
self.with_root(msg.tree_hash_root().0)
9798
}
99+
100+
pub fn with_nonce(self, nonce: u64) -> Self {
101+
Self { nonce, ..self }
102+
}
98103
}
99104

100105
impl Display for SignConsensusRequest {
101106
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102107
write!(
103108
f,
104-
"Consensus(pubkey: {}, object_root: {})",
109+
"Consensus(pubkey: {}, object_root: {}, nonce: {})",
105110
self.pubkey,
106-
hex::encode_prefixed(self.object_root)
111+
hex::encode_prefixed(self.object_root),
112+
self.nonce
107113
)
108114
}
109115
}
@@ -112,15 +118,16 @@ impl Display for SignConsensusRequest {
112118
pub struct SignProxyRequest<T: ProxyId> {
113119
pub proxy: T,
114120
pub object_root: B256,
121+
pub nonce: u64,
115122
}
116123

117124
impl<T: ProxyId> SignProxyRequest<T> {
118-
pub fn new(proxy: T, object_root: B256) -> Self {
119-
Self { proxy, object_root }
125+
pub fn new(proxy: T, object_root: B256, nonce: u64) -> Self {
126+
Self { proxy, object_root, nonce }
120127
}
121128

122129
pub fn builder(proxy: T) -> Self {
123-
Self::new(proxy, B256::ZERO)
130+
Self::new(proxy, B256::ZERO, u64::MAX - 1)
124131
}
125132

126133
pub fn with_root<R: Into<B256>>(self, object_root: R) -> Self {
@@ -130,15 +137,20 @@ impl<T: ProxyId> SignProxyRequest<T> {
130137
pub fn with_msg(self, msg: &impl TreeHash) -> Self {
131138
self.with_root(msg.tree_hash_root().0)
132139
}
140+
141+
pub fn with_nonce(self, nonce: u64) -> Self {
142+
Self { nonce, ..self }
143+
}
133144
}
134145

135146
impl Display for SignProxyRequest<BlsPublicKey> {
136147
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137148
write!(
138149
f,
139-
"BLS(proxy: {}, object_root: {})",
150+
"BLS(proxy: {}, object_root: {}, nonce: {})",
140151
self.proxy,
141-
hex::encode_prefixed(self.object_root)
152+
hex::encode_prefixed(self.object_root),
153+
self.nonce
142154
)
143155
}
144156
}
@@ -147,9 +159,10 @@ impl Display for SignProxyRequest<Address> {
147159
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148160
write!(
149161
f,
150-
"ECDSA(proxy: {}, object_root: {})",
162+
"ECDSA(proxy: {}, object_root: {}, nonce: {})",
151163
self.proxy,
152-
hex::encode_prefixed(self.object_root)
164+
hex::encode_prefixed(self.object_root),
165+
self.nonce
153166
)
154167
}
155168
}

crates/common/src/commit/response.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use alloy::{
2-
primitives::{Address, B256},
2+
primitives::{Address, B256, U256},
33
rpc::types::beacon::BlsSignature,
44
};
55
use serde::{Deserialize, Serialize};
@@ -11,6 +11,8 @@ pub struct BlsSignResponse {
1111
pub pubkey: BlsPublicKey,
1212
pub object_root: B256,
1313
pub module_signing_id: B256,
14+
pub nonce: u64,
15+
pub chain_id: U256,
1416
pub signature: BlsSignature,
1517
}
1618

@@ -19,9 +21,11 @@ impl BlsSignResponse {
1921
pubkey: BlsPublicKey,
2022
object_root: B256,
2123
module_signing_id: B256,
24+
nonce: u64,
25+
chain_id: U256,
2226
signature: BlsSignature,
2327
) -> Self {
24-
Self { pubkey, object_root, module_signing_id, signature }
28+
Self { pubkey, object_root, module_signing_id, nonce, chain_id, signature }
2529
}
2630
}
2731

@@ -30,6 +34,8 @@ pub struct EcdsaSignResponse {
3034
pub address: Address,
3135
pub object_root: B256,
3236
pub module_signing_id: B256,
37+
pub nonce: u64,
38+
pub chain_id: U256,
3339
pub signature: EcdsaSignature,
3440
}
3541

@@ -38,8 +44,10 @@ impl EcdsaSignResponse {
3844
address: Address,
3945
object_root: B256,
4046
module_signing_id: B256,
47+
nonce: u64,
48+
chain_id: U256,
4149
signature: EcdsaSignature,
4250
) -> Self {
43-
Self { address, object_root, module_signing_id, signature }
51+
Self { address, object_root, module_signing_id, nonce, chain_id, signature }
4452
}
4553
}

crates/common/src/config/pbs.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,13 @@ impl PbsConfig {
169169
if !matches!(chain, Chain::Custom { .. }) {
170170
let provider = ProviderBuilder::new().on_http(rpc_url.clone());
171171
let chain_id = provider.get_chain_id().await?;
172+
let chain_id_big = U256::from(chain_id);
172173
ensure!(
173-
chain_id == chain.id(),
174+
chain_id_big == chain.id(),
174175
"Rpc url is for the wrong chain, expected: {} ({:?}) got {}",
175176
chain.id(),
176177
chain,
177-
chain_id
178+
chain_id_big
178179
);
179180
}
180181
}

crates/common/src/pbs/types/get_header.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ mod tests {
177177
&parsed.message,
178178
&parsed.signature,
179179
None,
180-
&B32::from(APPLICATION_BUILDER_DOMAIN)
180+
&B32::from(APPLICATION_BUILDER_DOMAIN),
181181
)
182182
.is_ok())
183183
}

crates/common/src/signature.rs

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
constants::{COMMIT_BOOST_DOMAIN, GENESIS_VALIDATORS_ROOT},
1010
error::BlstErrorWrapper,
1111
signer::{verify_bls_signature, verify_ecdsa_signature, BlsSecretKey, EcdsaSignature},
12-
types::{self, Chain},
12+
types::{self, Chain, SignatureRequestInfo},
1313
};
1414

1515
pub fn sign_message(secret_key: &BlsSecretKey, msg: &[u8]) -> BlsSignature {
@@ -20,15 +20,19 @@ pub fn sign_message(secret_key: &BlsSecretKey, msg: &[u8]) -> BlsSignature {
2020
pub fn compute_prop_commit_signing_root(
2121
chain: Chain,
2222
object_root: &B256,
23-
module_signing_id: Option<&B256>,
23+
signature_request_info: Option<&SignatureRequestInfo>,
2424
domain_mask: &B32,
2525
) -> B256 {
2626
let domain = compute_domain(chain, domain_mask);
27-
match module_signing_id {
28-
Some(id) => {
29-
let object_root =
30-
types::PropCommitSigningInfo { data: *object_root, module_signing_id: *id }
31-
.tree_hash_root();
27+
match signature_request_info {
28+
Some(SignatureRequestInfo { module_signing_id, nonce }) => {
29+
let object_root = types::PropCommitSigningInfo {
30+
data: *object_root,
31+
module_signing_id: *module_signing_id,
32+
nonce: *nonce,
33+
chain_id: chain.id(),
34+
}
35+
.tree_hash_root();
3236
types::SigningData { object_root, signing_domain: domain }.tree_hash_root()
3337
}
3438
None => types::SigningData { object_root: *object_root, signing_domain: domain }
@@ -63,13 +67,13 @@ pub fn verify_signed_message<T: TreeHash>(
6367
pubkey: &BlsPublicKey,
6468
msg: &T,
6569
signature: &BlsSignature,
66-
module_signing_id: Option<&B256>,
70+
signature_request_info: Option<&SignatureRequestInfo>,
6771
domain_mask: &B32,
6872
) -> Result<(), BlstErrorWrapper> {
6973
let signing_root = compute_prop_commit_signing_root(
7074
chain,
7175
&msg.tree_hash_root(),
72-
module_signing_id,
76+
signature_request_info,
7377
domain_mask,
7478
);
7579
verify_bls_signature(pubkey, signing_root.as_slice(), signature)
@@ -100,12 +104,12 @@ pub fn sign_commit_boost_root(
100104
chain: Chain,
101105
secret_key: &BlsSecretKey,
102106
object_root: &B256,
103-
module_signing_id: Option<&B256>,
107+
signature_request_info: Option<&SignatureRequestInfo>,
104108
) -> BlsSignature {
105109
let signing_root = compute_prop_commit_signing_root(
106110
chain,
107111
object_root,
108-
module_signing_id,
112+
signature_request_info,
109113
&B32::from(COMMIT_BOOST_DOMAIN),
110114
);
111115
sign_message(secret_key, signing_root.as_slice())
@@ -123,11 +127,14 @@ pub fn verify_proposer_commitment_signature_bls(
123127
msg: &impl TreeHash,
124128
signature: &BlsSignature,
125129
module_signing_id: &B256,
130+
nonce: u64,
126131
) -> Result<(), BlstErrorWrapper> {
127132
let signing_domain = compute_domain(chain, &B32::from(COMMIT_BOOST_DOMAIN));
128133
let object_root = types::PropCommitSigningInfo {
129134
data: msg.tree_hash_root(),
130135
module_signing_id: *module_signing_id,
136+
nonce,
137+
chain_id: chain.id(),
131138
}
132139
.tree_hash_root();
133140
let signing_root = types::SigningData { object_root, signing_domain }.tree_hash_root();
@@ -142,12 +149,16 @@ pub fn verify_proposer_commitment_signature_ecdsa(
142149
msg: &impl TreeHash,
143150
signature: &EcdsaSignature,
144151
module_signing_id: &B256,
152+
nonce: u64,
145153
) -> Result<(), eyre::Report> {
146-
let object_root = msg.tree_hash_root();
147154
let signing_domain = compute_domain(chain, &B32::from(COMMIT_BOOST_DOMAIN));
148-
let object_root =
149-
types::PropCommitSigningInfo { data: object_root, module_signing_id: *module_signing_id }
150-
.tree_hash_root();
155+
let object_root = types::PropCommitSigningInfo {
156+
data: msg.tree_hash_root(),
157+
module_signing_id: *module_signing_id,
158+
nonce,
159+
chain_id: chain.id(),
160+
}
161+
.tree_hash_root();
151162
let signing_root = types::SigningData { object_root, signing_domain }.tree_hash_root();
152163
verify_ecdsa_signature(address, &signing_root, signature)
153164
}

crates/common/src/signer/schemes/bls.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use blst::BLST_ERROR;
44
use tree_hash::TreeHash;
55

66
use crate::{
7-
error::BlstErrorWrapper, signature::sign_commit_boost_root, types::Chain,
7+
error::BlstErrorWrapper,
8+
signature::sign_commit_boost_root,
9+
types::{Chain, SignatureRequestInfo},
810
utils::blst_pubkey_to_alloy,
911
};
1012

@@ -42,11 +44,11 @@ impl BlsSigner {
4244
&self,
4345
chain: Chain,
4446
object_root: &B256,
45-
module_signing_id: Option<&B256>,
47+
signature_request_info: Option<&SignatureRequestInfo>,
4648
) -> BlsSignature {
4749
match self {
4850
BlsSigner::Local(sk) => {
49-
sign_commit_boost_root(chain, sk, object_root, module_signing_id)
51+
sign_commit_boost_root(chain, sk, object_root, signature_request_info)
5052
}
5153
}
5254
}
@@ -55,9 +57,9 @@ impl BlsSigner {
5557
&self,
5658
chain: Chain,
5759
msg: &impl TreeHash,
58-
module_signing_id: Option<&B256>,
60+
signature_request_info: Option<&SignatureRequestInfo>,
5961
) -> BlsSignature {
60-
self.sign(chain, &msg.tree_hash_root(), module_signing_id).await
62+
self.sign(chain, &msg.tree_hash_root(), signature_request_info).await
6163
}
6264
}
6365

0 commit comments

Comments
 (0)