Skip to content

Commit b92c4c8

Browse files
authored
Merge branch 'develop' into chore/consistent-log-label-signer-signature-hash
2 parents cbf2234 + 3a8bb6d commit b92c4c8

File tree

17 files changed

+3404
-7004
lines changed

17 files changed

+3404
-7004
lines changed

.github/workflows/bitcoin-tests.yml

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,30 +70,13 @@ jobs:
7070
- test-name: tests::neon_integrations::lockup_integration
7171
- test-name: tests::neon_integrations::most_recent_utxo_integration_test
7272
- test-name: tests::neon_integrations::run_with_custom_wallet
73-
- test-name: tests::neon_integrations::test_competing_miners_build_anchor_blocks_and_microblocks_on_same_chain
7473
- test-name: tests::neon_integrations::test_competing_miners_build_anchor_blocks_on_same_chain_without_rbf
7574
- test-name: tests::neon_integrations::test_one_miner_build_anchor_blocks_on_same_chain_without_rbf
7675
- test-name: tests::signer::v0::tenure_extend_after_2_bad_commits
7776
- test-name: tests::stackerdb::test_stackerdb_event_observer
7877
- test-name: tests::stackerdb::test_stackerdb_load_store
79-
# Microblock tests that are no longer needed on every CI run
80-
# (microblocks are unsupported starting in Epoch 2.5)
81-
- test-name: tests::neon_integrations::bad_microblock_pubkey
82-
- test-name: tests::neon_integrations::microblock_fork_poison_integration_test
83-
- test-name: tests::neon_integrations::microblock_integration_test
84-
- test-name: tests::neon_integrations::microblock_large_tx_integration_test_FLAKY
85-
- test-name: tests::neon_integrations::microblock_limit_hit_integration_test
86-
- test-name: tests::neon_integrations::microblock_miner_multiple_attempts
87-
- test-name: tests::neon_integrations::test_problematic_microblocks_are_not_mined
88-
- test-name: tests::neon_integrations::test_problematic_microblocks_are_not_relayed_or_stored
89-
- test-name: tests::neon_integrations::runtime_overflow_unconfirmed_microblocks_integration_test
90-
- test-name: tests::neon_integrations::size_overflow_unconfirmed_invalid_stream_microblocks_integration_test
91-
- test-name: tests::neon_integrations::size_overflow_unconfirmed_microblocks_integration_test
92-
- test-name: tests::neon_integrations::size_overflow_unconfirmed_stream_microblocks_integration_test
93-
- test-name: tests::epoch_25::microblocks_disabled
9478
# Epoch tests are covered by the epoch-tests CI workflow, and don't need to run
9579
# on every PR (for older epochs)
96-
- test-name: tests::epoch_205::bigger_microblock_streams_in_2_05
9780
- test-name: tests::epoch_205::test_cost_limit_switch_version205
9881
- test-name: tests::epoch_205::test_dynamic_db_method_costs
9982
- test-name: tests::epoch_205::test_exact_block_costs

.github/workflows/epoch-tests.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ jobs:
2929
max-parallel: 32
3030
matrix:
3131
test-name:
32-
- tests::epoch_205::bigger_microblock_streams_in_2_05
3332
- tests::epoch_205::test_cost_limit_switch_version205
3433
- tests::epoch_205::test_dynamic_db_method_costs
3534
- tests::epoch_205::test_exact_block_costs

Cargo.lock

Lines changed: 11 additions & 43 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

stacks-common/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ features = ["arbitrary_precision", "unbounded_depth"]
5050
workspace = true
5151

5252
[dependencies.curve25519-dalek]
53-
version = "=2.0.0"
53+
version = "4.1.3"
5454
features = ["serde"]
5555

5656
[dependencies.time]

stacks-common/src/util/vrf.rs

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use std::{error, fmt};
2626

2727
use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
2828
use curve25519_dalek::edwards::{CompressedEdwardsY, EdwardsPoint};
29-
use curve25519_dalek::scalar::Scalar as ed25519_Scalar;
29+
use curve25519_dalek::scalar::{clamp_integer, Scalar as ed25519_Scalar};
3030
use rand;
3131
use sha2::{Digest, Sha512};
3232

@@ -181,6 +181,7 @@ impl VRFPublicKey {
181181
pub enum Error {
182182
InvalidPublicKey,
183183
InvalidDataError,
184+
InvalidHashPoints,
184185
OSRNGError(rand::Error),
185186
}
186187

@@ -189,6 +190,7 @@ impl fmt::Display for Error {
189190
match *self {
190191
Error::InvalidPublicKey => write!(f, "Invalid public key"),
191192
Error::InvalidDataError => write!(f, "No data could be found"),
193+
Error::InvalidHashPoints => write!(f, "VRF hash points did not yield a valid scalar"),
192194
Error::OSRNGError(ref e) => fmt::Display::fmt(e, f),
193195
}
194196
}
@@ -199,6 +201,7 @@ impl error::Error for Error {
199201
match *self {
200202
Error::InvalidPublicKey => None,
201203
Error::InvalidDataError => None,
204+
Error::InvalidHashPoints => None,
202205
Error::OSRNGError(ref e) => Some(e),
203206
}
204207
}
@@ -246,7 +249,7 @@ impl VRFProof {
246249

247250
#[allow(clippy::needless_range_loop)]
248251
pub fn check_c(c: &ed25519_Scalar) -> bool {
249-
let c_bytes = c.reduce().to_bytes();
252+
let c_bytes = c.to_bytes();
250253

251254
// upper 16 bytes of c must be 0's
252255
for c_byte in c_bytes[16..32].iter() {
@@ -281,7 +284,9 @@ impl VRFProof {
281284
// 0 32 48 80
282285
// |----------------------------|----------|---------------------------|
283286
// Gamma point c scalar s scalar
284-
let gamma_opt = CompressedEdwardsY::from_slice(&bytes[0..32]).decompress();
287+
let gamma_opt = CompressedEdwardsY::from_slice(&bytes[0..32])
288+
.ok()
289+
.and_then(|y| y.decompress());
285290
if gamma_opt.is_none() {
286291
test_debug!("Invalid Gamma");
287292
return None;
@@ -297,10 +302,14 @@ impl VRFProof {
297302

298303
c_buf[..16].copy_from_slice(&bytes[32..(16 + 32)]);
299304
s_buf[..32].copy_from_slice(&bytes[48..(32 + 48)]);
300-
let c = ed25519_Scalar::from_canonical_bytes(c_buf)?;
301-
let s = ed25519_Scalar::from_canonical_bytes(s_buf)?;
302-
303-
Some(VRFProof { Gamma: gamma, c, s })
305+
let c: Option<ed25519_Scalar> = ed25519_Scalar::from_canonical_bytes(c_buf).into();
306+
let s: Option<ed25519_Scalar> = ed25519_Scalar::from_canonical_bytes(s_buf).into();
307+
308+
Some(VRFProof {
309+
Gamma: gamma,
310+
c: c?,
311+
s: s?,
312+
})
304313
}
305314
_ => None,
306315
}
@@ -324,7 +333,7 @@ impl VRFProof {
324333
"FATAL ERROR: somehow constructed an invalid ECVRF proof"
325334
);
326335

327-
let c_bytes = self.c.reduce().to_bytes();
336+
let c_bytes = self.c.to_bytes();
328337
c_bytes_16[0..16].copy_from_slice(&c_bytes[0..16]);
329338

330339
let gamma_bytes = self.Gamma.compress().to_bytes();
@@ -386,7 +395,7 @@ impl VRF {
386395
}
387396

388397
let y = CompressedEdwardsY::from_slice(&hasher.finalize()[0..32]);
389-
if let Some(h) = y.decompress() {
398+
if let Some(h) = y.ok().and_then(|y| y.decompress()) {
390399
break h;
391400
}
392401

@@ -445,8 +454,7 @@ impl VRF {
445454
let mut h_32 = [0u8; 32];
446455
h_32.copy_from_slice(&h[0..32]);
447456

448-
let x_scalar_raw = ed25519_Scalar::from_bits(h_32);
449-
let x_scalar = x_scalar_raw.reduce(); // use the canonical scalar for the private key
457+
let x_scalar = ed25519_Scalar::from_bytes_mod_order(clamp_integer(h_32));
450458

451459
trunc_hash.copy_from_slice(&h[32..64]);
452460

@@ -469,17 +477,17 @@ impl VRF {
469477

470478
/// Convert a 16-byte string into a scalar.
471479
/// The upper 16 bytes in the resulting scalar MUST BE 0's
472-
fn ed25519_scalar_from_hash128(hash128: &[u8; 16]) -> ed25519_Scalar {
480+
fn ed25519_scalar_from_hash128(hash128: &[u8; 16]) -> Option<ed25519_Scalar> {
473481
let mut scalar_buf = [0u8; 32];
474482
scalar_buf[0..16].copy_from_slice(hash128);
475483

476-
ed25519_Scalar::from_bits(scalar_buf)
484+
ed25519_Scalar::from_canonical_bytes(scalar_buf).into()
477485
}
478486

479487
/// ECVRF proof routine
480488
/// https://tools.ietf.org/id/draft-irtf-cfrg-vrf-02.html#rfc.section.5.1
481489
#[allow(clippy::op_ref)]
482-
pub fn prove(secret: &VRFPrivateKey, alpha: &[u8]) -> VRFProof {
490+
pub fn prove(secret: &VRFPrivateKey, alpha: &[u8]) -> Option<VRFProof> {
483491
let (Y_point, x_scalar, trunc_hash) = VRF::expand_privkey(secret);
484492
let H_point = VRF::hash_to_curve(&Y_point, alpha);
485493

@@ -490,15 +498,15 @@ impl VRF {
490498
let kH_point = &k_scalar * &H_point;
491499

492500
let c_hashbuf = VRF::hash_points(&H_point, &Gamma_point, &kB_point, &kH_point);
493-
let c_scalar = VRF::ed25519_scalar_from_hash128(&c_hashbuf);
501+
let c_scalar = VRF::ed25519_scalar_from_hash128(&c_hashbuf)?;
494502

495-
let s_full_scalar = &k_scalar + &c_scalar * &x_scalar;
496-
let s_scalar = s_full_scalar.reduce();
503+
let s_scalar = &k_scalar + &c_scalar * &x_scalar;
497504

498505
// NOTE: expect() won't panic because c_scalar is guaranteed to have
499506
// its upper 16 bytes as 0
500507
VRFProof::new(Gamma_point, c_scalar, s_scalar)
501-
.expect("FATAL ERROR: upper-16 bytes of proof's C scalar are NOT 0")
508+
.inspect_err(|e| error!("FATAL: upper-16 bytes of proof's C scalar are NOT 0: {e}"))
509+
.ok()
502510
}
503511

504512
/// Given a public key, verify that the private key owner that generate the ECVRF proof did so on the given message.
@@ -509,19 +517,21 @@ impl VRF {
509517
#[allow(clippy::op_ref)]
510518
pub fn verify(Y_point: &VRFPublicKey, proof: &VRFProof, alpha: &[u8]) -> Result<bool, Error> {
511519
let H_point = VRF::hash_to_curve(Y_point, alpha);
512-
let s_reduced = proof.s().reduce();
520+
let s_reduced = proof.s();
513521
let Y_point_ed = CompressedEdwardsY(Y_point.to_bytes())
514522
.decompress()
515523
.ok_or(Error::InvalidPublicKey)?;
516524
if proof.Gamma().is_small_order() {
517525
return Err(Error::InvalidPublicKey);
518526
}
519527

520-
let U_point = &s_reduced * &ED25519_BASEPOINT_POINT - proof.c() * Y_point_ed;
521-
let V_point = &s_reduced * &H_point - proof.c() * proof.Gamma();
528+
let U_point = s_reduced * &ED25519_BASEPOINT_POINT - proof.c() * Y_point_ed;
529+
let V_point = s_reduced * &H_point - proof.c() * proof.Gamma();
522530

523531
let c_prime_hashbuf = VRF::hash_points(&H_point, proof.Gamma(), &U_point, &V_point);
524-
let c_prime = VRF::ed25519_scalar_from_hash128(&c_prime_hashbuf);
532+
let Some(c_prime) = VRF::ed25519_scalar_from_hash128(&c_prime_hashbuf) else {
533+
return Err(Error::InvalidHashPoints);
534+
};
525535

526536
// NOTE: this leverages constant-time comparison inherited from the Scalar impl
527537
Ok(c_prime == *(proof.c()))
@@ -583,7 +593,7 @@ mod tests {
583593
let privk = VRFPrivateKey::from_bytes(&proof_fixture.privkey[..]).unwrap();
584594
let expected_proof_bytes = &proof_fixture.proof[..];
585595

586-
let proof = VRF::prove(&privk, &alpha.to_vec());
596+
let proof = VRF::prove(&privk, &alpha.to_vec()).unwrap();
587597
let proof_bytes = proof.to_bytes();
588598

589599
assert_eq!(proof_bytes.to_vec(), expected_proof_bytes.to_vec());
@@ -605,7 +615,7 @@ mod tests {
605615
let mut msg = [0u8; 1024];
606616
rng.fill_bytes(&mut msg);
607617

608-
let proof = VRF::prove(&secret_key, &msg);
618+
let proof = VRF::prove(&secret_key, &msg).unwrap();
609619
let res = VRF::verify(&public_key, &proof, &msg).unwrap();
610620

611621
assert!(res);

0 commit comments

Comments
 (0)