Use const values for our traits where we can

This commit is contained in:
Luke Parker 2022-06-03 23:22:08 -04:00
parent b83ca7d666
commit 3617ed4eb7
No known key found for this signature in database
GPG key ID: F9F1386DB1E119B6
12 changed files with 72 additions and 113 deletions

View file

@ -57,25 +57,12 @@ impl<D: Digest<OutputSize = U64>, const WIDE: bool> Curve for Ed25519Internal<D,
type G = dfg::EdwardsPoint; type G = dfg::EdwardsPoint;
type T = &'static dfg::EdwardsBasepointTable; type T = &'static dfg::EdwardsBasepointTable;
fn id_len() -> u8 { const ID: &'static [u8] = b"edwards25519";
u8::try_from(Self::id().len()).unwrap()
}
fn id() -> &'static [u8] { const GENERATOR: Self::G = dfg::ED25519_BASEPOINT_POINT;
b"edwards25519" const GENERATOR_TABLE: Self::T = &dfg::ED25519_BASEPOINT_TABLE;
}
fn generator() -> Self::G { const LITTLE_ENDIAN: bool = true;
Self::G::generator()
}
fn generator_table() -> Self::T {
&dfg::ED25519_BASEPOINT_TABLE
}
fn little_endian() -> bool {
true
}
fn random_nonce<R: RngCore + CryptoRng>(secret: Self::F, rng: &mut R) -> Self::F { fn random_nonce<R: RngCore + CryptoRng>(secret: Self::F, rng: &mut R) -> Self::F {
let mut seed = vec![0; 32]; let mut seed = vec![0; 32];

View file

@ -41,7 +41,7 @@ fn generate_key_r1<R: RngCore + CryptoRng, C: Curve>(
// Step 1: Generate t random values to form a polynomial with // Step 1: Generate t random values to form a polynomial with
coefficients.push(C::F::random(&mut *rng)); coefficients.push(C::F::random(&mut *rng));
// Step 3: Generate public commitments // Step 3: Generate public commitments
commitments.push(C::generator_table() * coefficients[i]); commitments.push(C::GENERATOR_TABLE * coefficients[i]);
// Serialize them for publication // Serialize them for publication
serialized.extend(&C::G_to_bytes(&commitments[i])); serialized.extend(&C::G_to_bytes(&commitments[i]));
} }
@ -59,7 +59,7 @@ fn generate_key_r1<R: RngCore + CryptoRng, C: Curve>(
challenge::<C>( challenge::<C>(
context, context,
params.i(), params.i(),
&C::G_to_bytes(&(C::generator_table() * r)), &C::G_to_bytes(&(C::GENERATOR_TABLE * r)),
&serialized &serialized
) )
).serialize() ).serialize()
@ -224,7 +224,7 @@ fn complete_r2<R: RngCore + CryptoRng, C: Curve>(
res res
}; };
let mut batch = BatchVerifier::new(shares.len(), C::little_endian()); let mut batch = BatchVerifier::new(shares.len(), C::LITTLE_ENDIAN);
for (l, share) in &shares { for (l, share) in &shares {
if *l == params.i() { if *l == params.i() {
continue; continue;
@ -237,7 +237,7 @@ fn complete_r2<R: RngCore + CryptoRng, C: Curve>(
// ensure that malleability isn't present is to use this n * t algorithm, which runs // ensure that malleability isn't present is to use this n * t algorithm, which runs
// per sender and not as an aggregate of all senders, which also enables blame // per sender and not as an aggregate of all senders, which also enables blame
let mut values = exponential(params.i, &commitments[l]); let mut values = exponential(params.i, &commitments[l]);
values.push((-*share, C::generator())); values.push((-*share, C::GENERATOR));
batch.queue(rng, *l, values); batch.queue(rng, *l, values);
} }
batch.verify_with_vartime_blame().map_err(|l| FrostError::InvalidCommitment(l))?; batch.verify_with_vartime_blame().map_err(|l| FrostError::InvalidCommitment(l))?;
@ -254,9 +254,9 @@ fn complete_r2<R: RngCore + CryptoRng, C: Curve>(
// Calculate each user's verification share // Calculate each user's verification share
let mut verification_shares = HashMap::new(); let mut verification_shares = HashMap::new();
for i in 1 ..= params.n() { for i in 1 ..= params.n() {
verification_shares.insert(i, multiexp_vartime(exponential(i, &stripes), C::little_endian())); verification_shares.insert(i, multiexp_vartime(exponential(i, &stripes), C::LITTLE_ENDIAN));
} }
debug_assert_eq!(C::generator_table() * secret_share, verification_shares[&params.i()]); debug_assert_eq!(C::GENERATOR_TABLE * secret_share, verification_shares[&params.i()]);
// TODO: Clear serialized and shares // TODO: Clear serialized and shares

View file

@ -42,22 +42,19 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug {
/// Precomputed table type /// Precomputed table type
type T: Mul<Self::F, Output = Self::G>; type T: Mul<Self::F, Output = Self::G>;
/// Byte length of the curve ID
// While C::id().len() is trivial, this bounds it to u8 for any proper Curve implementation
fn id_len() -> u8;
/// ID for this curve /// ID for this curve
fn id() -> &'static [u8]; const ID: &'static [u8];
/// Generator for the group /// Generator for the group
// While group does provide this in its API, Jubjub users will want to use a custom basepoint // While group does provide this in its API, privacy coins will want to use a custom basepoint
fn generator() -> Self::G; const GENERATOR: Self::G;
/// Table for the generator for the group /// Table for the generator for the group
/// If there isn't a precomputed table available, the generator itself should be used /// If there isn't a precomputed table available, the generator itself should be used
fn generator_table() -> Self::T; const GENERATOR_TABLE: Self::T;
/// If little endian is used for the scalar field's Repr /// If little endian is used for the scalar field's Repr
fn little_endian() -> bool; const LITTLE_ENDIAN: bool;
/// Securely generate a random nonce. H4 from the IETF draft /// Securely generate a random nonce. H4 from the IETF draft
fn random_nonce<R: RngCore + CryptoRng>(secret: Self::F, rng: &mut R) -> Self::F; fn random_nonce<R: RngCore + CryptoRng>(secret: Self::F, rng: &mut R) -> Self::F;
@ -298,12 +295,12 @@ impl<C: Curve> MultisigKeys<C> {
let offset_share = offset * C::F::from(included.len().try_into().unwrap()).invert().unwrap(); let offset_share = offset * C::F::from(included.len().try_into().unwrap()).invert().unwrap();
Ok(MultisigView { Ok(MultisigView {
group_key: self.group_key + (C::generator_table() * offset), group_key: self.group_key + (C::GENERATOR_TABLE * offset),
secret_share: secret_share + offset_share, secret_share: secret_share + offset_share,
verification_shares: self.verification_shares.iter().map( verification_shares: self.verification_shares.iter().map(
|(l, share)| ( |(l, share)| (
*l, *l,
(*share * lagrange::<C::F>(*l, &included)) + (C::generator_table() * offset_share) (*share * lagrange::<C::F>(*l, &included)) + (C::GENERATOR_TABLE * offset_share)
) )
).collect(), ).collect(),
included: included.to_vec(), included: included.to_vec(),
@ -311,15 +308,13 @@ impl<C: Curve> MultisigKeys<C> {
} }
pub fn serialized_len(n: u16) -> usize { pub fn serialized_len(n: u16) -> usize {
1 + usize::from(C::id_len()) + (3 * 2) + C::F_len() + C::G_len() + (usize::from(n) * C::G_len()) 8 + C::ID.len() + (3 * 2) + C::F_len() + C::G_len() + (usize::from(n) * C::G_len())
} }
pub fn serialize(&self) -> Vec<u8> { pub fn serialize(&self) -> Vec<u8> {
let mut serialized = Vec::with_capacity( let mut serialized = Vec::with_capacity(MultisigKeys::<C>::serialized_len(self.params.n));
1 + usize::from(C::id_len()) + MultisigKeys::<C>::serialized_len(self.params.n) serialized.extend(u64::try_from(C::ID.len()).unwrap().to_be_bytes());
); serialized.extend(C::ID);
serialized.push(C::id_len());
serialized.extend(C::id());
serialized.extend(&self.params.t.to_be_bytes()); serialized.extend(&self.params.t.to_be_bytes());
serialized.extend(&self.params.n.to_be_bytes()); serialized.extend(&self.params.n.to_be_bytes());
serialized.extend(&self.params.i.to_be_bytes()); serialized.extend(&self.params.i.to_be_bytes());
@ -328,34 +323,28 @@ impl<C: Curve> MultisigKeys<C> {
for l in 1 ..= self.params.n.into() { for l in 1 ..= self.params.n.into() {
serialized.extend(&C::G_to_bytes(&self.verification_shares[&l])); serialized.extend(&C::G_to_bytes(&self.verification_shares[&l]));
} }
serialized serialized
} }
pub fn deserialize(serialized: &[u8]) -> Result<MultisigKeys<C>, FrostError> { pub fn deserialize(serialized: &[u8]) -> Result<MultisigKeys<C>, FrostError> {
if serialized.len() < 1 { let mut start = u64::try_from(C::ID.len()).unwrap().to_be_bytes().to_vec();
Err(FrostError::InternalError("MultisigKeys serialization is empty".to_string()))?; start.extend(C::ID);
let mut cursor = start.len();
if serialized.len() < (cursor + 4) {
Err(
FrostError::InternalError(
"MultisigKeys serialization is missing its curve/participant quantities".to_string()
)
)?;
} }
if &start != &serialized[.. cursor] {
let id_len: usize = serialized[0].into();
let mut cursor = 1;
if serialized.len() < (cursor + id_len) {
Err(FrostError::InternalError("ID wasn't included".to_string()))?;
}
if C::id() != &serialized[cursor .. (cursor + id_len)] {
Err( Err(
FrostError::InternalError( FrostError::InternalError(
"curve is distinct between serialization and deserialization".to_string() "curve is distinct between serialization and deserialization".to_string()
) )
)?; )?;
} }
cursor += id_len;
if serialized.len() < (cursor + 4) {
Err(FrostError::InternalError("participant quantities weren't included".to_string()))?;
}
let t = u16::from_be_bytes(serialized[cursor .. (cursor + 2)].try_into().unwrap()); let t = u16::from_be_bytes(serialized[cursor .. (cursor + 2)].try_into().unwrap());
cursor += 2; cursor += 2;

View file

@ -28,7 +28,7 @@ pub(crate) fn sign<C: Curve>(
challenge: C::F challenge: C::F
) -> SchnorrSignature<C> { ) -> SchnorrSignature<C> {
SchnorrSignature { SchnorrSignature {
R: C::generator_table() * nonce, R: C::GENERATOR_TABLE * nonce,
s: nonce + (private_key * challenge) s: nonce + (private_key * challenge)
} }
} }
@ -38,15 +38,15 @@ pub(crate) fn verify<C: Curve>(
challenge: C::F, challenge: C::F,
signature: &SchnorrSignature<C> signature: &SchnorrSignature<C>
) -> bool { ) -> bool {
(C::generator_table() * signature.s) == (signature.R + (public_key * challenge)) (C::GENERATOR_TABLE * signature.s) == (signature.R + (public_key * challenge))
} }
pub(crate) fn batch_verify<C: Curve, R: RngCore + CryptoRng>( pub(crate) fn batch_verify<C: Curve, R: RngCore + CryptoRng>(
rng: &mut R, rng: &mut R,
triplets: &[(u16, C::G, C::F, SchnorrSignature<C>)] triplets: &[(u16, C::G, C::F, SchnorrSignature<C>)]
) -> Result<(), u16> { ) -> Result<(), u16> {
let mut values = [(C::F::one(), C::generator()); 3]; let mut values = [(C::F::one(), C::GENERATOR); 3];
let mut batch = BatchVerifier::new(triplets.len(), C::little_endian()); let mut batch = BatchVerifier::new(triplets.len(), C::LITTLE_ENDIAN);
for triple in triplets { for triple in triplets {
// s = r + ca // s = r + ca
// sG == R + cA // sG == R + cA

View file

@ -84,7 +84,7 @@ fn preprocess<R: RngCore + CryptoRng, C: Curve, A: Algorithm<C>>(
C::random_nonce(params.view().secret_share(), &mut *rng), C::random_nonce(params.view().secret_share(), &mut *rng),
C::random_nonce(params.view().secret_share(), &mut *rng) C::random_nonce(params.view().secret_share(), &mut *rng)
]; ];
let commitments = [C::generator_table() * nonces[0], C::generator_table() * nonces[1]]; let commitments = [C::GENERATOR_TABLE * nonces[0], C::GENERATOR_TABLE * nonces[1]];
let mut serialized = C::G_to_bytes(&commitments[0]); let mut serialized = C::G_to_bytes(&commitments[0]);
serialized.extend(&C::G_to_bytes(&commitments[1])); serialized.extend(&C::G_to_bytes(&commitments[1]));

View file

@ -82,25 +82,12 @@ impl Curve for P256 {
type G = ProjectivePoint; type G = ProjectivePoint;
type T = ProjectivePoint; type T = ProjectivePoint;
fn id_len() -> u8 { const ID: &'static [u8] = b"P-256";
u8::try_from(Self::id().len()).unwrap()
}
fn id() -> &'static [u8] { const GENERATOR: Self::G = Self::G::GENERATOR;
b"P-256" const GENERATOR_TABLE: Self::G = Self::G::GENERATOR;
}
fn generator() -> Self::G { const LITTLE_ENDIAN: bool = false;
Self::G::GENERATOR
}
fn generator_table() -> Self::T {
Self::G::GENERATOR
}
fn little_endian() -> bool {
false
}
fn random_nonce<R: RngCore + CryptoRng>(secret: Self::F, rng: &mut R) -> Self::F { fn random_nonce<R: RngCore + CryptoRng>(secret: Self::F, rng: &mut R) -> Self::F {
let mut seed = vec![0; 32]; let mut seed = vec![0; 32];

View file

@ -113,7 +113,7 @@ pub fn recover<C: Curve>(keys: &HashMap<u16, MultisigKeys<C>>) -> C::F {
C::F::zero(), C::F::zero(),
|accum, (i, keys)| accum + (keys.secret_share() * lagrange::<C::F>(*i, &included)) |accum, (i, keys)| accum + (keys.secret_share() * lagrange::<C::F>(*i, &included))
); );
assert_eq!(C::generator_table() * group_private, first.group_key(), "failed to recover keys"); assert_eq!(C::GENERATOR_TABLE * group_private, first.group_key(), "failed to recover keys");
group_private group_private
} }

View file

@ -15,7 +15,7 @@ pub(crate) fn core_sign<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
let challenge = C::F::random(rng); // Doesn't bother to craft an HRAM let challenge = C::F::random(rng); // Doesn't bother to craft an HRAM
assert!( assert!(
schnorr::verify::<C>( schnorr::verify::<C>(
C::generator_table() * private_key, C::GENERATOR_TABLE * private_key,
challenge, challenge,
&schnorr::sign(private_key, nonce, challenge) &schnorr::sign(private_key, nonce, challenge)
) )
@ -28,9 +28,9 @@ pub(crate) fn core_sign<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
pub(crate) fn core_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) { pub(crate) fn core_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
assert!( assert!(
!schnorr::verify::<C>( !schnorr::verify::<C>(
C::generator_table() * C::F::random(&mut *rng), C::GENERATOR_TABLE * C::F::random(&mut *rng),
C::F::random(rng), C::F::random(rng),
&SchnorrSignature { R: C::generator_table() * C::F::zero(), s: C::F::zero() } &SchnorrSignature { R: C::GENERATOR_TABLE * C::F::zero(), s: C::F::zero() }
) )
); );
} }
@ -48,7 +48,7 @@ pub(crate) fn core_batch_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
// Batch verify // Batch verify
let triplets = (0 .. 5).map( let triplets = (0 .. 5).map(
|i| (u16::try_from(i + 1).unwrap(), C::generator_table() * keys[i], challenges[i], sigs[i]) |i| (u16::try_from(i + 1).unwrap(), C::GENERATOR_TABLE * keys[i], challenges[i], sigs[i])
).collect::<Vec<_>>(); ).collect::<Vec<_>>();
schnorr::batch_verify(rng, &triplets).unwrap(); schnorr::batch_verify(rng, &triplets).unwrap();
@ -113,7 +113,7 @@ fn sign_with_offset<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
for i in 1 ..= u16::try_from(keys.len()).unwrap() { for i in 1 ..= u16::try_from(keys.len()).unwrap() {
keys.insert(i, Rc::new(keys[&i].offset(offset))); keys.insert(i, Rc::new(keys[&i].offset(offset)));
} }
let offset_key = group_key + (C::generator_table() * offset); let offset_key = group_key + (C::GENERATOR_TABLE * offset);
sign_core(rng, offset_key, &keys); sign_core(rng, offset_key, &keys);
} }

View file

@ -26,14 +26,14 @@ fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, Multisi
|secret| C::F_from_slice(&hex::decode(secret).unwrap()).unwrap() |secret| C::F_from_slice(&hex::decode(secret).unwrap()).unwrap()
).collect::<Vec<_>>(); ).collect::<Vec<_>>();
let verification_shares = shares.iter().map( let verification_shares = shares.iter().map(
|secret| C::generator() * secret |secret| C::GENERATOR * secret
).collect::<Vec<_>>(); ).collect::<Vec<_>>();
let mut keys = HashMap::new(); let mut keys = HashMap::new();
for i in 1 ..= u16::try_from(shares.len()).unwrap() { for i in 1 ..= u16::try_from(shares.len()).unwrap() {
let mut serialized = vec![]; let mut serialized = vec![];
serialized.push(C::id_len()); serialized.extend(u64::try_from(C::ID.len()).unwrap().to_be_bytes());
serialized.extend(C::id()); serialized.extend(C::ID);
serialized.extend(vectors.threshold.to_be_bytes()); serialized.extend(vectors.threshold.to_be_bytes());
serialized.extend(u16::try_from(shares.len()).unwrap().to_be_bytes()); serialized.extend(u16::try_from(shares.len()).unwrap().to_be_bytes());
serialized.extend(i.to_be_bytes()); serialized.extend(i.to_be_bytes());
@ -59,7 +59,7 @@ pub fn vectors<C: Curve, H: Hram<C>>(vectors: Vectors) {
let keys = vectors_to_multisig_keys::<C>(&vectors); let keys = vectors_to_multisig_keys::<C>(&vectors);
let group_key = C::G_from_slice(&hex::decode(vectors.group_key).unwrap()).unwrap(); let group_key = C::G_from_slice(&hex::decode(vectors.group_key).unwrap()).unwrap();
assert_eq!( assert_eq!(
C::generator() * C::F_from_slice(&hex::decode(vectors.group_secret).unwrap()).unwrap(), C::GENERATOR * C::F_from_slice(&hex::decode(vectors.group_secret).unwrap()).unwrap(),
group_key group_key
); );
assert_eq!( assert_eq!(
@ -87,8 +87,8 @@ pub fn vectors<C: Curve, H: Hram<C>>(vectors: Vectors) {
C::F_from_slice(&hex::decode(vectors.nonces[c][1]).unwrap()).unwrap() C::F_from_slice(&hex::decode(vectors.nonces[c][1]).unwrap()).unwrap()
]; ];
let mut serialized = C::G_to_bytes(&(C::generator() * nonces[0])); let mut serialized = C::G_to_bytes(&(C::GENERATOR * nonces[0]));
serialized.extend(&C::G_to_bytes(&(C::generator() * nonces[1]))); serialized.extend(&C::G_to_bytes(&(C::GENERATOR * nonces[1])));
machine.unsafe_override_preprocess( machine.unsafe_override_preprocess(
PreprocessPackage { nonces, serialized: serialized.clone() } PreprocessPackage { nonces, serialized: serialized.clone() }

View file

@ -58,7 +58,7 @@ impl Monero {
pub fn new(url: String) -> Monero { pub fn new(url: String) -> Monero {
Monero { Monero {
rpc: Rpc::new(url), rpc: Rpc::new(url),
view: dfg::Scalar::from_hash(view_key::<Monero>(0)).0 view: *view_key::<Monero>(0)
} }
} }
} }
@ -73,16 +73,16 @@ impl Coin for Monero {
type Address = Address; type Address = Address;
fn id() -> &'static [u8] { b"Monero" } const ID: &'static [u8] = b"Monero";
fn confirmations() -> usize { 10 } const CONFIRMATIONS: usize = 10;
// Testnet TX bb4d188a4c571f2f0de70dca9d475abc19078c10ffa8def26dd4f63ce1bcfd79 uses 146 inputs // Testnet TX bb4d188a4c571f2f0de70dca9d475abc19078c10ffa8def26dd4f63ce1bcfd79 uses 146 inputs
// while using less than 100kb of space, albeit with just 2 outputs (though outputs share a BP) // while using less than 100kb of space, albeit with just 2 outputs (though outputs share a BP)
// The TX size limit is half the contextual median block weight, where said weight is >= 300,000 // The TX size limit is half the contextual median block weight, where said weight is >= 300,000
// This means any TX which fits into 150kb will be accepted by Monero // This means any TX which fits into 150kb will be accepted by Monero
// 128, even with 16 outputs, should fit into 100kb. Further efficiency by 192 may be viable // 128, even with 16 outputs, should fit into 100kb. Further efficiency by 192 may be viable
// TODO: Get hard numbers and tune // TODO: Get hard numbers and tune
fn max_inputs() -> usize { 128 } const MAX_INPUTS: usize = 128;
fn max_outputs() -> usize { 16 } const MAX_OUTPUTS: usize = 16;
async fn get_height(&self) -> Result<usize, CoinError> { async fn get_height(&self) -> Result<usize, CoinError> {
self.rpc.get_height().await.map_err(|_| CoinError::ConnectionError) self.rpc.get_height().await.map_err(|_| CoinError::ConnectionError)

View file

@ -4,8 +4,6 @@ use async_trait::async_trait;
use thiserror::Error; use thiserror::Error;
use rand_core::{RngCore, CryptoRng}; use rand_core::{RngCore, CryptoRng};
use blake2::{digest::{Digest, Update}, Blake2b512};
use frost::{Curve, MultisigKeys}; use frost::{Curve, MultisigKeys};
mod coins; mod coins;
@ -40,10 +38,10 @@ pub trait Coin {
type Address: Send; type Address: Send;
fn id() -> &'static [u8]; const ID: &'static [u8];
fn confirmations() -> usize; const CONFIRMATIONS: usize;
fn max_inputs() -> usize; const MAX_INPUTS: usize;
fn max_outputs() -> usize; const MAX_OUTPUTS: usize;
async fn get_height(&self) -> Result<usize, CoinError>; async fn get_height(&self) -> Result<usize, CoinError>;
async fn get_block(&self, height: usize) -> Result<Self::Block, CoinError>; async fn get_block(&self, height: usize) -> Result<Self::Block, CoinError>;
@ -70,11 +68,9 @@ pub trait Coin {
) -> Result<(Vec<u8>, Vec<<Self::Output as Output>::Id>), CoinError>; ) -> Result<(Vec<u8>, Vec<<Self::Output as Output>::Id>), CoinError>;
} }
// Generate a view key for a given chain in a globally consistent manner regardless of the current // Generate a static view key for a given chain in a globally consistent manner
// group key // Doesn't consider the current group key to increase the simplicity of verifying Serai's status
// Takes an index, k, for more modern privacy protocols which use multiple view keys // Takes an index, k, for more modern privacy protocols which use multiple view keys
// Doesn't run Curve::hash_to_F, instead returning the hash object, due to hash_to_F being a FROST pub fn view_key<C: Coin>(k: u64) -> <C::Curve as Curve>::F {
// definition instead of a wide reduction from a hash object C::Curve::hash_to_F(b"Serai DEX View Key", &[C::ID, &k.to_le_bytes()].concat())
pub fn view_key<C: Coin>(k: u64) -> Blake2b512 {
Blake2b512::new().chain(b"Serai DEX View Key").chain(C::id()).chain(k.to_le_bytes())
} }

View file

@ -16,7 +16,7 @@ impl<C: Curve> WalletKeys<C> {
} }
// Bind this key to a specific network by applying an additive offset // Bind this key to a specific network by applying an additive offset
// While it would be fine to just C::id(), including the group key creates distinct // While it would be fine to just C::ID, including the group key creates distinct
// offsets instead of static offsets. Under a statically offset system, a BTC key could // offsets instead of static offsets. Under a statically offset system, a BTC key could
// have X subtracted to find the potential group key, and then have Y added to find the // have X subtracted to find the potential group key, and then have Y added to find the
// potential ETH group key. While this shouldn't be an issue, as this isn't a private // potential ETH group key. While this shouldn't be an issue, as this isn't a private
@ -27,7 +27,7 @@ impl<C: Curve> WalletKeys<C> {
const DST: &[u8] = b"Serai Processor Wallet Chain Bind"; const DST: &[u8] = b"Serai Processor Wallet Chain Bind";
let mut transcript = DigestTranscript::<blake2::Blake2b512>::new(DST); let mut transcript = DigestTranscript::<blake2::Blake2b512>::new(DST);
transcript.append_message(b"chain", chain); transcript.append_message(b"chain", chain);
transcript.append_message(b"curve", C::id()); transcript.append_message(b"curve", C::ID);
transcript.append_message(b"group_key", &C::G_to_bytes(&self.keys.group_key())); transcript.append_message(b"group_key", &C::G_to_bytes(&self.keys.group_key()));
self.keys.offset(C::hash_to_F(DST, &transcript.challenge(b"offset"))) self.keys.offset(C::hash_to_F(DST, &transcript.challenge(b"offset")))
} }
@ -73,11 +73,11 @@ impl<C: Coin> Wallet<C> {
pub fn add_keys(&mut self, keys: &WalletKeys<C::Curve>) { pub fn add_keys(&mut self, keys: &WalletKeys<C::Curve>) {
// Doesn't use +1 as this is height, not block index, and poll moves by block index // Doesn't use +1 as this is height, not block index, and poll moves by block index
self.pending.push((self.acknowledged_height(keys.creation_height), keys.bind(C::id()))); self.pending.push((self.acknowledged_height(keys.creation_height), keys.bind(C::ID)));
} }
pub async fn poll(&mut self) -> Result<(), CoinError> { pub async fn poll(&mut self) -> Result<(), CoinError> {
let confirmed_height = self.coin.get_height().await? - C::confirmations(); let confirmed_height = self.coin.get_height().await? - C::CONFIRMATIONS;
for height in self.scanned_height() .. confirmed_height { for height in self.scanned_height() .. confirmed_height {
// If any keys activated at this height, shift them over // If any keys activated at this height, shift them over
{ {
@ -114,7 +114,7 @@ impl<C: Coin> Wallet<C> {
let acknowledged_height = self.acknowledged_height(canonical); let acknowledged_height = self.acknowledged_height(canonical);
// TODO: Log schedule outputs when max_outputs is low // TODO: Log schedule outputs when MAX_OUTPUTS is low
// Payments is the first set of TXs in the schedule // Payments is the first set of TXs in the schedule
// As each payment re-appears, let mut payments = schedule[payment] where the only input is // As each payment re-appears, let mut payments = schedule[payment] where the only input is
// the source payment // the source payment
@ -129,7 +129,7 @@ impl<C: Coin> Wallet<C> {
while outputs.len() != 0 { while outputs.len() != 0 {
// Select the maximum amount of outputs possible // Select the maximum amount of outputs possible
let mut inputs = &outputs[0 .. C::max_inputs().min(outputs.len())]; let mut inputs = &outputs[0 .. C::MAX_INPUTS.min(outputs.len())];
// Calculate their sum value, minus the fee needed to spend them // Calculate their sum value, minus the fee needed to spend them
let mut sum = inputs.iter().map(|input| input.amount()).sum::<u64>(); let mut sum = inputs.iter().map(|input| input.amount()).sum::<u64>();