mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-23 03:59:22 +00:00
Add Transaction::sign.
While I don't love the introduction of empty_signed, it's practically fine.
This commit is contained in:
parent
3f6565588f
commit
710e6e5217
6 changed files with 67 additions and 75 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -10769,7 +10769,6 @@ dependencies = [
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"rand_chacha 0.3.1",
|
"rand_chacha 0.3.1",
|
||||||
"rand_core 0.6.4",
|
|
||||||
"schnorr-signatures",
|
"schnorr-signatures",
|
||||||
"serai-db",
|
"serai-db",
|
||||||
"subtle",
|
"subtle",
|
||||||
|
|
|
@ -17,6 +17,7 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
|
|
||||||
zeroize = "^1.5"
|
zeroize = "^1.5"
|
||||||
|
rand_core = "0.6"
|
||||||
|
|
||||||
blake2 = "0.10"
|
blake2 = "0.10"
|
||||||
|
|
||||||
|
@ -40,6 +41,4 @@ log = "0.4"
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand_core = "0.6"
|
|
||||||
|
|
||||||
tributary = { package = "tributary-chain", path = "./tributary", features = ["tests"] }
|
tributary = { package = "tributary-chain", path = "./tributary", features = ["tests"] }
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
use rand_core::{RngCore, OsRng};
|
use rand_core::{RngCore, OsRng};
|
||||||
|
|
||||||
use ciphersuite::{group::ff::Field, Ciphersuite, Ristretto};
|
use ciphersuite::{Ciphersuite, Ristretto};
|
||||||
use schnorr::SchnorrSignature;
|
|
||||||
use frost::Participant;
|
use frost::Participant;
|
||||||
|
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
@ -17,7 +15,7 @@ use processor_messages::{
|
||||||
CoordinatorMessage,
|
CoordinatorMessage,
|
||||||
};
|
};
|
||||||
|
|
||||||
use tributary::{Signed, Transaction as TransactionTrait, Tributary};
|
use tributary::Tributary;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
processor::MemProcessor,
|
processor::MemProcessor,
|
||||||
|
@ -39,41 +37,14 @@ async fn dkg_commitments_test() {
|
||||||
let mut txs = vec![];
|
let mut txs = vec![];
|
||||||
// Create DKG commitments for each key
|
// Create DKG commitments for each key
|
||||||
for key in &keys {
|
for key in &keys {
|
||||||
let pub_key = Ristretto::generator() * **key;
|
|
||||||
|
|
||||||
let attempt = 0;
|
let attempt = 0;
|
||||||
let mut commitments = vec![0; 256];
|
let mut commitments = vec![0; 256];
|
||||||
OsRng.fill_bytes(&mut commitments);
|
OsRng.fill_bytes(&mut commitments);
|
||||||
|
|
||||||
// Create the TX with a null signature so we can get its sig hash
|
let mut tx =
|
||||||
let tx = Transaction::DkgCommitments(
|
Transaction::DkgCommitments(attempt, commitments.clone(), Transaction::empty_signed());
|
||||||
attempt,
|
tx.sign(&mut OsRng, spec.genesis(), key, 0);
|
||||||
commitments.clone(),
|
txs.push(tx);
|
||||||
Signed {
|
|
||||||
signer: pub_key,
|
|
||||||
nonce: 0,
|
|
||||||
signature: SchnorrSignature::<Ristretto> {
|
|
||||||
R: Ristretto::generator(),
|
|
||||||
s: <Ristretto as Ciphersuite>::F::ZERO,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Re-create it with the actual signature
|
|
||||||
// We could mutate the existing one, we'd just have to match to the DkgCommitments enum variant
|
|
||||||
txs.push(Transaction::DkgCommitments(
|
|
||||||
attempt,
|
|
||||||
commitments,
|
|
||||||
Signed {
|
|
||||||
signer: pub_key,
|
|
||||||
nonce: 0,
|
|
||||||
signature: SchnorrSignature::<Ristretto>::sign(
|
|
||||||
key,
|
|
||||||
Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng)),
|
|
||||||
tx.sig_hash(spec.genesis()),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut last_block = tributaries[0].1.tip();
|
let mut last_block = tributaries[0].1.tip();
|
||||||
|
|
|
@ -1,17 +1,12 @@
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
|
||||||
use zeroize::Zeroizing;
|
|
||||||
|
|
||||||
use rand_core::{RngCore, OsRng};
|
use rand_core::{RngCore, OsRng};
|
||||||
|
|
||||||
use ciphersuite::{group::ff::Field, Ciphersuite, Ristretto};
|
|
||||||
use schnorr::SchnorrSignature;
|
|
||||||
|
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
||||||
use serai_db::MemDb;
|
use serai_db::MemDb;
|
||||||
|
|
||||||
use tributary::{Signed, Transaction as TransactionTrait, Tributary};
|
use tributary::Tributary;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
LocalP2p,
|
LocalP2p,
|
||||||
|
@ -33,41 +28,15 @@ async fn tx_test() {
|
||||||
let sender =
|
let sender =
|
||||||
usize::try_from(OsRng.next_u64() % u64::try_from(tributaries.len()).unwrap()).unwrap();
|
usize::try_from(OsRng.next_u64() % u64::try_from(tributaries.len()).unwrap()).unwrap();
|
||||||
let key = keys[sender].clone();
|
let key = keys[sender].clone();
|
||||||
let pub_key = Ristretto::generator() * *key;
|
|
||||||
|
|
||||||
let attempt = 0;
|
let attempt = 0;
|
||||||
let mut commitments = vec![0; 256];
|
let mut commitments = vec![0; 256];
|
||||||
OsRng.fill_bytes(&mut commitments);
|
OsRng.fill_bytes(&mut commitments);
|
||||||
|
|
||||||
// Create the TX with a null signature so we can get its sig hash
|
// Create the TX with a null signature so we can get its sig hash
|
||||||
let tx = Transaction::DkgCommitments(
|
let mut tx =
|
||||||
attempt,
|
Transaction::DkgCommitments(attempt, commitments.clone(), Transaction::empty_signed());
|
||||||
commitments.clone(),
|
tx.sign(&mut OsRng, spec.genesis(), &key, 0);
|
||||||
Signed {
|
|
||||||
signer: pub_key,
|
|
||||||
nonce: 0,
|
|
||||||
signature: SchnorrSignature::<Ristretto> {
|
|
||||||
R: Ristretto::generator(),
|
|
||||||
s: <Ristretto as Ciphersuite>::F::ZERO,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Re-create it with the actual signature
|
|
||||||
// We could mutate the existing one, we'd just have to match to the DkgCommitments enum variant
|
|
||||||
let tx = Transaction::DkgCommitments(
|
|
||||||
attempt,
|
|
||||||
commitments,
|
|
||||||
Signed {
|
|
||||||
signer: pub_key,
|
|
||||||
nonce: 0,
|
|
||||||
signature: SchnorrSignature::<Ristretto>::sign(
|
|
||||||
&key,
|
|
||||||
Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng)),
|
|
||||||
tx.sig_hash(spec.genesis()),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(tributaries[sender].1.add_transaction(tx.clone()).await);
|
assert!(tributaries[sender].1.add_transaction(tx.clone()).await);
|
||||||
// Sleep for two blocks
|
// Sleep for two blocks
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
|
use core::ops::Deref;
|
||||||
use std::{io, collections::HashMap};
|
use std::{io, collections::HashMap};
|
||||||
|
|
||||||
|
use zeroize::Zeroizing;
|
||||||
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
use blake2::{Digest, Blake2s256};
|
use blake2::{Digest, Blake2s256};
|
||||||
use transcript::{Transcript, RecommendedTranscript};
|
use transcript::{Transcript, RecommendedTranscript};
|
||||||
|
|
||||||
use ciphersuite::{Ciphersuite, Ristretto};
|
use ciphersuite::{group::ff::Field, Ciphersuite, Ristretto};
|
||||||
|
use schnorr::SchnorrSignature;
|
||||||
use frost::Participant;
|
use frost::Participant;
|
||||||
|
|
||||||
use scale::Encode;
|
use scale::Encode;
|
||||||
|
@ -349,3 +354,53 @@ impl TransactionTrait for Transaction {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Transaction {
|
||||||
|
// Used to initially construct transactions so we can then get sig hashes and perform signing
|
||||||
|
pub fn empty_signed() -> Signed {
|
||||||
|
Signed {
|
||||||
|
signer: Ristretto::generator(),
|
||||||
|
nonce: 0,
|
||||||
|
signature: SchnorrSignature::<Ristretto> {
|
||||||
|
R: Ristretto::generator(),
|
||||||
|
s: <Ristretto as Ciphersuite>::F::ZERO,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign a transaction
|
||||||
|
pub fn sign<R: RngCore + CryptoRng>(
|
||||||
|
&mut self,
|
||||||
|
rng: &mut R,
|
||||||
|
genesis: [u8; 32],
|
||||||
|
key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
|
||||||
|
nonce: u32,
|
||||||
|
) {
|
||||||
|
fn signed(tx: &mut Transaction) -> &mut Signed {
|
||||||
|
match tx {
|
||||||
|
Transaction::DkgCommitments(_, _, ref mut signed) => signed,
|
||||||
|
Transaction::DkgShares(_, _, ref mut signed) => signed,
|
||||||
|
|
||||||
|
Transaction::ExternalBlock(_) => panic!("signing ExternalBlock"),
|
||||||
|
Transaction::SubstrateBlock(_) => panic!("signing SubstrateBlock"),
|
||||||
|
|
||||||
|
Transaction::BatchPreprocess(ref mut data) => &mut data.signed,
|
||||||
|
Transaction::BatchShare(ref mut data) => &mut data.signed,
|
||||||
|
|
||||||
|
Transaction::SignPreprocess(ref mut data) => &mut data.signed,
|
||||||
|
Transaction::SignShare(ref mut data) => &mut data.signed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let signed_ref = signed(self);
|
||||||
|
signed_ref.signer = Ristretto::generator() * key.deref();
|
||||||
|
signed_ref.nonce = nonce;
|
||||||
|
|
||||||
|
let sig_hash = self.sig_hash(genesis);
|
||||||
|
signed(self).signature = SchnorrSignature::<Ristretto>::sign(
|
||||||
|
key,
|
||||||
|
Zeroizing::new(<Ristretto as Ciphersuite>::F::random(rng)),
|
||||||
|
sig_hash,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ tokio = { version = "1", features = ["macros", "sync", "time", "rt"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
zeroize = "^1.5"
|
zeroize = "^1.5"
|
||||||
rand_core = "0.6"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
tests = []
|
tests = []
|
||||||
|
|
Loading…
Reference in a new issue