diff --git a/.github/actions/bitcoin/action.yml b/.github/actions/bitcoin/action.yml index 5a5cd068..b2b36ecf 100644 --- a/.github/actions/bitcoin/action.yml +++ b/.github/actions/bitcoin/action.yml @@ -5,7 +5,7 @@ inputs: version: description: "Version to download and run" required: false - default: "27.0" + default: "29.1" runs: using: "composite" diff --git a/.github/actions/test-dependencies/action.yml b/.github/actions/test-dependencies/action.yml index c2a3ba59..7e63b877 100644 --- a/.github/actions/test-dependencies/action.yml +++ b/.github/actions/test-dependencies/action.yml @@ -10,7 +10,7 @@ inputs: bitcoin-version: description: "Bitcoin version to download and run as a regtest node" required: false - default: "27.1" + default: "29.1" runs: using: "composite" diff --git a/coordinator/tributary-sdk/src/blockchain.rs b/coordinator/tributary-sdk/src/blockchain.rs index 70a44106..2224517d 100644 --- a/coordinator/tributary-sdk/src/blockchain.rs +++ b/coordinator/tributary-sdk/src/blockchain.rs @@ -21,7 +21,7 @@ pub(crate) struct Blockchain { block_number: u64, tip: [u8; 32], - participants: HashSet<::G>, + participants: HashSet<[u8; 32]>, provided: ProvidedTransactions, mempool: Mempool, @@ -74,7 +74,10 @@ impl Blockchain { let mut res = Self { db: Some(db.clone()), genesis, - participants: participants.iter().copied().collect(), + participants: participants + .iter() + .map(<::G as GroupEncoding>::to_bytes) + .collect(), block_number: 0, tip: genesis, @@ -173,7 +176,7 @@ impl Blockchain { self.mempool.add::( |signer, order| { - if self.participants.contains(&signer) { + if self.participants.contains(&signer.to_bytes()) { Some( db.get(Self::next_nonce_key(&self.genesis, &signer, &order)) .map_or(0, |bytes| u32::from_le_bytes(bytes.try_into().unwrap())), @@ -202,7 +205,7 @@ impl Blockchain { if let Some(next_nonce) = self.mempool.next_nonce_in_mempool(signer, order.to_vec()) { return Some(next_nonce); } - if self.participants.contains(signer) { + if self.participants.contains(&signer.to_bytes()) { Some( self .db @@ -251,7 +254,7 @@ impl Blockchain { self.tip, self.provided.transactions.clone(), &mut |signer, order| { - if self.participants.contains(signer) { + if self.participants.contains(&signer.to_bytes()) { let key = Self::next_nonce_key(&self.genesis, signer, order); let next = txn .get(&key) diff --git a/coordinator/tributary-sdk/src/mempool.rs b/coordinator/tributary-sdk/src/mempool.rs index f0d99a42..20b4de8f 100644 --- a/coordinator/tributary-sdk/src/mempool.rs +++ b/coordinator/tributary-sdk/src/mempool.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use dalek_ff_group::Ristretto; -use ciphersuite::*; +use ciphersuite::{group::GroupEncoding, *}; use serai_db::{DbTxn, Db}; @@ -21,9 +21,9 @@ pub(crate) struct Mempool { db: D, genesis: [u8; 32], - last_nonce_in_mempool: HashMap<(::G, Vec), u32>, + last_nonce_in_mempool: HashMap<([u8; 32], Vec), u32>, txs: HashMap<[u8; 32], Transaction>, - txs_per_signer: HashMap<::G, u32>, + txs_per_signer: HashMap<[u8; 32], u32>, } impl Mempool { @@ -82,6 +82,7 @@ impl Mempool { } Transaction::Application(tx) => match tx.kind() { TransactionKind::Signed(order, Signed { signer, nonce, .. }) => { + let signer = signer.to_bytes(); let amount = *res.txs_per_signer.get(&signer).unwrap_or(&0) + 1; res.txs_per_signer.insert(signer, amount); @@ -140,6 +141,8 @@ impl Mempool { }; let mut next_nonce = blockchain_next_nonce; + let signer = signer.to_bytes(); + if let Some(mempool_last_nonce) = self.last_nonce_in_mempool.get(&(signer, order.clone())) { @@ -182,7 +185,7 @@ impl Mempool { signer: &::G, order: Vec, ) -> Option { - self.last_nonce_in_mempool.get(&(*signer, order)).copied().map(|nonce| nonce + 1) + self.last_nonce_in_mempool.get(&(signer.to_bytes(), order)).copied().map(|nonce| nonce + 1) } /// Get transactions to include in a block. @@ -243,6 +246,8 @@ impl Mempool { if let Some(tx) = self.txs.remove(tx) { if let TransactionKind::Signed(order, Signed { signer, nonce, .. }) = tx.kind() { + let signer = signer.to_bytes(); + let amount = *self.txs_per_signer.get(&signer).unwrap() - 1; self.txs_per_signer.insert(signer, amount); diff --git a/crypto/dalek-ff-group/src/lib.rs b/crypto/dalek-ff-group/src/lib.rs index 563ae40a..c9c9b228 100644 --- a/crypto/dalek-ff-group/src/lib.rs +++ b/crypto/dalek-ff-group/src/lib.rs @@ -8,7 +8,6 @@ use core::{ borrow::Borrow, ops::{Deref, Add, AddAssign, Sub, SubAssign, Neg, Mul, MulAssign}, iter::{Iterator, Sum}, - hash::{Hash, Hasher}, }; use zeroize::Zeroize; @@ -20,9 +19,8 @@ use subtle::{Choice, CtOption}; use curve25519_dalek::{ edwards::{EdwardsPoint as DEdwardsPoint, CompressedEdwardsY}, - ristretto::{RistrettoPoint as DRistrettoPoint, CompressedRistretto}, }; -pub use curve25519_dalek::Scalar; +pub use curve25519_dalek::{Scalar, ristretto::RistrettoPoint}; use ::ciphersuite::group::{Group, GroupEncoding, prime::PrimeGroup}; @@ -259,17 +257,6 @@ macro_rules! dalek_group { } impl PrimeGroup for $Point {} - - // Support being used as a key in a table - // While it is expensive as a key, due to the field operations required, there's frequently - // use cases for public key -> value lookups - #[allow(unknown_lints, renamed_and_removed_lints)] - #[allow(clippy::derived_hash_with_manual_eq, clippy::derive_hash_xor_eq)] - impl Hash for $Point { - fn hash(&self, state: &mut H) { - self.to_bytes().hash(state); - } - } }; } @@ -281,14 +268,6 @@ dalek_group!( CompressedEdwardsY, ); -dalek_group!( - RistrettoPoint, - DRistrettoPoint, - |_| true, - RistrettoBasepointTable, - CompressedRistretto, -); - #[test] fn test_ed25519_group() { ff_group_tests::group::test_prime_group_bits::<_, EdwardsPoint>(&mut rand_core::OsRng); diff --git a/crypto/prime-field/src/lib.rs b/crypto/prime-field/src/lib.rs index 6733fc85..ff4f36f3 100644 --- a/crypto/prime-field/src/lib.rs +++ b/crypto/prime-field/src/lib.rs @@ -419,7 +419,7 @@ macro_rules! odd_prime_field_with_specific_repr { const ONE_MOD_EIGHT: bool = (MODULUS.as_words()[0] % 8) == 1; const FIVE_MOD_EIGHT: bool = (MODULUS.as_words()[0] % 8) == 5; - let sqrt = if THREE_MOD_FOUR { + let mut sqrt = if THREE_MOD_FOUR { const SQRT_EXP: UnderlyingUint = MODULUS.shr_vartime(2).wrapping_add(&UnderlyingUint::ONE); Self(self.0.pow(&SQRT_EXP)) @@ -449,7 +449,10 @@ macro_rules! odd_prime_field_with_specific_repr { Self(upsilon * self.0 * (i - Self::ONE.0)) }; - let sqrt = <_>::conditional_select(&sqrt, &-sqrt, sqrt.0.retrieve().is_odd()); + // Normalize to the even choice of square root + // `let ()` is used to assert how `conditional_negate` operates in-place + let () = sqrt.conditional_negate(sqrt.is_odd()); + CtOption::new(sqrt, sqrt.square().ct_eq(self)) } fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { diff --git a/orchestration/src/networks/bitcoin.rs b/orchestration/src/networks/bitcoin.rs index 9136c997..c26b27d5 100644 --- a/orchestration/src/networks/bitcoin.rs +++ b/orchestration/src/networks/bitcoin.rs @@ -7,7 +7,7 @@ pub fn bitcoin(orchestration_path: &Path, network: Network) { const DOWNLOAD_BITCOIN: &str = r#" FROM alpine:latest AS bitcoin -ENV BITCOIN_VERSION=27.1 +ENV BITCOIN_VERSION=29.1 RUN apk --no-cache add wget git gnupg