Merge branch 'next' into next-polkadot-sdk

This commit is contained in:
Luke Parker
2025-09-03 16:44:26 -04:00
130 changed files with 1102 additions and 1172 deletions

View File

@@ -4,10 +4,7 @@ use zeroize::{Zeroize, Zeroizing};
use rand_core::OsRng;
use dalek_ff_group::Ristretto;
use ciphersuite::{
group::ff::{Field, PrimeField},
Ciphersuite,
};
use ciphersuite::{group::ff::PrimeField, WrappedGroup};
use schnorr_signatures::SchnorrSignature;
use tokio::{
@@ -22,8 +19,8 @@ use crate::{Service, Metadata, QueuedMessage, MessageQueueRequest, message_chall
pub struct MessageQueue {
pub service: Service,
priv_key: Zeroizing<<Ristretto as Ciphersuite>::F>,
pub_key: <Ristretto as Ciphersuite>::G,
priv_key: Zeroizing<<Ristretto as WrappedGroup>::F>,
pub_key: <Ristretto as WrappedGroup>::G,
url: String,
}
@@ -31,7 +28,7 @@ impl MessageQueue {
pub fn new(
service: Service,
mut url: String,
priv_key: Zeroizing<<Ristretto as Ciphersuite>::F>,
priv_key: Zeroizing<<Ristretto as WrappedGroup>::F>,
) -> MessageQueue {
// Allow MESSAGE_QUEUE_RPC to either be a full URL or just a hostname
// While we could stitch together multiple variables, our control over this service makes this
@@ -46,16 +43,16 @@ impl MessageQueue {
pub fn from_env(service: Service) -> MessageQueue {
let url = env::var("MESSAGE_QUEUE_RPC").expect("message-queue RPC wasn't specified");
let priv_key: Zeroizing<<Ristretto as Ciphersuite>::F> = {
let priv_key: Zeroizing<<Ristretto as WrappedGroup>::F> = {
let key_str =
Zeroizing::new(env::var("MESSAGE_QUEUE_KEY").expect("message-queue key wasn't specified"));
let key_bytes = Zeroizing::new(
hex::decode(&key_str).expect("invalid message-queue key specified (wasn't hex)"),
);
let mut bytes = <<Ristretto as Ciphersuite>::F as PrimeField>::Repr::default();
let mut bytes = <<Ristretto as WrappedGroup>::F as PrimeField>::Repr::default();
bytes.copy_from_slice(&key_bytes);
let key = Zeroizing::new(
Option::from(<<Ristretto as Ciphersuite>::F as PrimeField>::from_repr(bytes))
Option::from(<<Ristretto as WrappedGroup>::F as PrimeField>::from_repr(bytes))
.expect("invalid message-queue key specified"),
);
bytes.zeroize();
@@ -79,7 +76,7 @@ impl MessageQueue {
}
pub async fn queue(&self, metadata: Metadata, msg: Vec<u8>) -> Result<(), String> {
let nonce = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
let nonce = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng));
let nonce_pub = Ristretto::generator() * nonce.deref();
let sig = SchnorrSignature::<Ristretto>::sign(
&self.priv_key,
@@ -215,7 +212,7 @@ impl MessageQueue {
pub async fn ack(&self, from: Service, id: u64) {
// TODO: Should this use OsRng? Deterministic or deterministic + random may be better.
let nonce = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
let nonce = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng));
let nonce_pub = Ristretto::generator() * nonce.deref();
let sig = SchnorrSignature::<Ristretto>::sign(
&self.priv_key,

View File

@@ -4,7 +4,7 @@ pub(crate) use std::{
};
use dalek_ff_group::Ristretto;
pub(crate) use ciphersuite::{group::GroupEncoding, Ciphersuite};
pub(crate) use ciphersuite::{group::GroupEncoding, WrappedGroup, GroupCanonicalEncoding};
pub(crate) use schnorr_signatures::SchnorrSignature;
pub(crate) use serai_primitives::network_id::ExternalNetworkId;
@@ -29,7 +29,7 @@ pub(crate) type Db = serai_db::RocksDB;
mod clippy {
use super::*;
use once_cell::sync::Lazy;
pub(crate) static KEYS: Lazy<Arc<RwLock<HashMap<Service, <Ristretto as Ciphersuite>::G>>>> =
pub(crate) static KEYS: Lazy<Arc<RwLock<HashMap<Service, <Ristretto as WrappedGroup>::G>>>> =
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
pub(crate) static QUEUES: Lazy<Arc<RwLock<HashMap<(Service, Service), RwLock<Queue<Db>>>>>> =
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
@@ -189,9 +189,9 @@ async fn main() {
let read_key = |str| {
let key = serai_env::var(str)?;
let mut repr = <<Ristretto as Ciphersuite>::G as GroupEncoding>::Repr::default();
let mut repr = <<Ristretto as WrappedGroup>::G as GroupEncoding>::Repr::default();
repr.as_mut().copy_from_slice(&hex::decode(key).unwrap());
Some(<Ristretto as Ciphersuite>::G::from_bytes(&repr).unwrap())
Some(<Ristretto as GroupCanonicalEncoding>::from_canonical_bytes(&repr).unwrap())
};
let register_service = |service, key| {

View File

@@ -1,6 +1,6 @@
use transcript::{Transcript, RecommendedTranscript};
use transcript::{Transcript, DigestTranscript};
use dalek_ff_group::Ristretto;
use ciphersuite::{group::GroupEncoding, Ciphersuite};
use ciphersuite::{group::GroupEncoding, FromUniformBytes, WrappedGroup, WithPreferredHash};
use borsh::{BorshSerialize, BorshDeserialize};
@@ -36,13 +36,15 @@ pub enum MessageQueueRequest {
pub fn message_challenge(
from: Service,
from_key: <Ristretto as Ciphersuite>::G,
from_key: <Ristretto as WrappedGroup>::G,
to: Service,
intent: &[u8],
msg: &[u8],
nonce: <Ristretto as Ciphersuite>::G,
) -> <Ristretto as Ciphersuite>::F {
let mut transcript = RecommendedTranscript::new(b"Serai Message Queue v0.1 Message");
nonce: <Ristretto as WrappedGroup>::G,
) -> <Ristretto as WrappedGroup>::F {
let mut transcript = DigestTranscript::<<Ristretto as WithPreferredHash>::H>::new(
b"Serai Message Queue v0.1 Message",
);
transcript.domain_separate(b"metadata");
transcript.append_message(b"from", borsh::to_vec(&from).unwrap());
transcript.append_message(b"from_key", from_key.to_bytes());
@@ -52,17 +54,19 @@ pub fn message_challenge(
transcript.append_message(b"msg", msg);
transcript.domain_separate(b"signature");
transcript.append_message(b"nonce", nonce.to_bytes());
<Ristretto as Ciphersuite>::hash_to_F(&transcript.challenge(b"challenge"))
<Ristretto as WrappedGroup>::F::from_uniform_bytes(&transcript.challenge(b"challenge").into())
}
pub fn ack_challenge(
to: Service,
to_key: <Ristretto as Ciphersuite>::G,
to_key: <Ristretto as WrappedGroup>::G,
from: Service,
id: u64,
nonce: <Ristretto as Ciphersuite>::G,
) -> <Ristretto as Ciphersuite>::F {
let mut transcript = RecommendedTranscript::new(b"Serai Message Queue v0.1 Acknowledgement");
nonce: <Ristretto as WrappedGroup>::G,
) -> <Ristretto as WrappedGroup>::F {
let mut transcript = DigestTranscript::<<Ristretto as WithPreferredHash>::H>::new(
b"Serai Message Queue v0.1 Acknowledgement",
);
transcript.domain_separate(b"metadata");
transcript.append_message(b"to", borsh::to_vec(&to).unwrap());
transcript.append_message(b"to_key", to_key.to_bytes());
@@ -71,5 +75,5 @@ pub fn ack_challenge(
transcript.append_message(b"id", id.to_le_bytes());
transcript.domain_separate(b"signature");
transcript.append_message(b"nonce", nonce.to_bytes());
<Ristretto as Ciphersuite>::hash_to_F(&transcript.challenge(b"challenge"))
<Ristretto as WrappedGroup>::F::from_uniform_bytes(&transcript.challenge(b"challenge").into())
}