farcaster_core 0.6.4

Farcaster project core library, blockchain atomic swaps.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
// Copyright 2021-2022 Farcaster Devs
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA

//! Cryptographic types (keys, signatures, commitments, etc) and traits (commit, generate key,
//! sign, etc) used to create the generic framework for supporting multiple blockchains under the
//! same interface.

use std::convert::TryInto;
use std::error;
use std::fmt::{self, Debug};
use std::io;

use thiserror::Error;
use tiny_keccak::{Hasher, Keccak};

use crate::consensus::{self, CanonicalBytes, Decodable, Encodable};

#[cfg(feature = "experimental")]
#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))]
pub mod dleq;
#[cfg(feature = "experimental")]
#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))]
pub mod slip10;

/// List of cryptographic errors that can be encountered in cryptographic operations such as
/// signatures, proofs, key derivation, or commitments.
#[derive(Error, Debug)]
pub enum Error {
    /// The key identifier is not supported and the key cannot be derived.
    #[error("The key identifier is not supported and the key cannot be derived")]
    UnsupportedKey,
    /// The key or key identifier does not exists or is missing.
    #[error("The key or key identifier does not exists or is missing")]
    MissingKey,
    /// The signature does not pass the validation tests.
    #[error("The signature does not pass the validation")]
    InvalidSignature,
    /// The adaptor key is not valid.
    #[error("The adaptor key is not valid")]
    InvalidAdaptorKey,
    /// The adaptor signature does not pass the validation tests.
    #[error("The adaptor signature does not pass the validation")]
    InvalidEncryptedSignature,
    /// The proof does not pass the validation tests.
    #[error("The proof does not pass the validation")]
    InvalidProof,
    /// The commitment does not match the given value.
    #[error("The commitment does not match the given value")]
    InvalidCommitment,
    /// The Pedersen commitment does not match the given value.
    #[error("The Pedersen commitment does not match the given value")]
    InvalidPedersenCommitment,
    /// The ring signature does not recompute.
    #[error("The ring signature does not recompute")]
    InvalidRingSignature,
    /// The proof of knowledge signature is invalid.
    #[error("The proof of knowledge signature is invalid")]
    InvalidProofOfKnowledge,
    /// SLIP10 error when manipulating extended secret keys.
    #[error("SLIP10 error: {0}")]
    Slip10(#[from] slip10::Error),
    /// Any cryptographic error not part of this list.
    #[error("Cryptographic error: {0}")]
    Other(Box<dyn error::Error + Send + Sync>),
}

impl Error {
    /// Creates a new cryptographic error of type [`Self::Other`] with an arbitrary payload.
    pub fn new<E>(error: E) -> Self
    where
        E: Into<Box<dyn error::Error + Send + Sync>>,
    {
        Self::Other(error.into())
    }

    /// Consumes the `Error`, returning its inner error (if any).
    ///
    /// If this [`enum@Error`] was constructed via [`new`] then this function will return [`Some`],
    /// otherwise it will return [`None`].
    ///
    /// [`new`]: Error::new
    ///
    pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
        match self {
            Self::Other(error) => Some(error),
            _ => None,
        }
    }
}

/// Element `E` prefixed with a tag `T`. Used to tag content with some ids. Tag should be `Eq` to
/// be used in vectors or sets and identify the content. Tags can be [`ArbitratingKeyId`],
/// [`AccordantKeyId`] or any other type of identifiers.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct TaggedElement<T, E> {
    tag: T,
    elem: E,
}

impl<T, E> TaggedElement<T, E> {
    /// Create a new tagged element `E` with the tag `T`.
    pub fn new(tag: T, elem: E) -> Self {
        Self { tag, elem }
    }

    /// Returns the tag `T`.
    pub fn tag(&self) -> &T {
        &self.tag
    }

    /// Returns the element `E`.
    pub fn elem(&self) -> &E {
        &self.elem
    }
}

impl<T, E> fmt::Display for TaggedElement<T, E>
where
    T: fmt::Display,
    E: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<{}: {}>", self.tag, self.elem)
    }
}

impl<T, E> Encodable for TaggedElement<T, E>
where
    T: Encodable,
    E: CanonicalBytes,
{
    #[inline]
    fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
        let len = self.tag.consensus_encode(s)?;
        Ok(len + self.elem.as_canonical_bytes().consensus_encode(s)?)
    }
}

impl<T, E> Decodable for TaggedElement<T, E>
where
    T: Decodable,
    E: CanonicalBytes,
{
    #[inline]
    fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, consensus::Error> {
        let tag = T::consensus_decode(d)?;
        let elem = E::from_canonical_bytes(unwrap_vec_ref!(d).as_ref())?;
        Ok(TaggedElement { tag, elem })
    }
}

/// A vector of `T` tagged elements `E`.
pub type TaggedElements<T, E> = Vec<TaggedElement<T, E>>;

/// A vector of [`u16`] tagged keys of type `E`.
pub type TaggedExtraKeys<E> = Vec<TaggedElement<u16, E>>;

/// A vector of shared keys tagged with [`SharedKeyId`] of type `E`.
pub type TaggedSharedKeys<E> = Vec<TaggedElement<SharedKeyId, E>>;

/// List of all possible arbitrating keys as defined for the base protocol in the RFCs. Extra keys
/// can be defined with [`Self::Extra`] variant and an `u16` identifier. Those keys can be used for
/// extra off-chain protocol such as multi-signature or multi-party computation schemes.
#[derive(Debug, Clone, Copy, Display, Serialize, Deserialize)]
#[display(Debug)]
pub enum ArbitratingKeyId {
    /// Arbitrating key used to fund the [`Lockable`] transaction through [`Fundable`].
    ///
    /// [`Lockable`]: crate::transaction::Lockable
    /// [`Fundable`]: crate::transaction::Fundable
    Lock,
    /// Key used in the [`Buyable`] transaction.
    ///
    /// [`Buyable`]: crate::transaction::Buyable
    Buy,
    /// Key used in the [`Cancelable`] transaction.
    ///
    /// [`Cancelable`]: crate::transaction::Cancelable
    Cancel,
    /// Key used in the [`Refundable`] transaction.
    ///
    /// [`Refundable`]: crate::transaction::Refundable
    Refund,
    /// Key used in the [`Punishable`] transaction.
    ///
    /// [`Punishable`]: crate::transaction::Punishable
    Punish,
    /// Any other key used for extra off-chain protocol such as multi-signature or multi-party
    /// computation schemes. Contains its own identifier. The identifier must not conflict with
    /// defined identifiers in RFCs.
    Extra(u16),
}

/// Defines the base accordant key identifier [`Self::Spend`] and all possible extra keys with
/// [`Self::Extra`] variant containing the `u16` identifier.
#[derive(Debug, Clone, Copy, Display, Serialize, Deserialize)]
#[display(Debug)]
pub enum AccordantKeyId {
    /// Accordant bought/sold key over the arbitrating blockchain.
    Spend,
    /// Any other key needed in the context of an accordant blockchain. Contains its own
    /// identifier.  The identifier must not conflict with defined identifiers in RFCs.
    Extra(u16),
}

/// Identifier for shared private keys over the arbitrating and accordant blockchains. E.g. the
/// `view` key needed to parse the Monero blockchain is a shared private key.
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Display, Serialize, Deserialize)]
#[display(Debug)]
pub struct SharedKeyId(u16);

impl SharedKeyId {
    /// Create a new shared key identifier.
    pub fn new(id: u16) -> Self {
        Self(id)
    }

    /// Return the identifier value.
    pub fn id(&self) -> u16 {
        self.0
    }
}

impl Encodable for SharedKeyId {
    #[inline]
    fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
        self.0.consensus_encode(s)
    }
}

impl Decodable for SharedKeyId {
    #[inline]
    fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, consensus::Error> {
        Ok(Self(u16::consensus_decode(d)?))
    }
}

/// The full set of keys (secret and public) a swap role has after the reveal round for the
/// [`Accordant`] blockchain in the swap (e.g. the Monero blockchain).
///
/// [`Accordant`]: crate::role::Accordant
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccordantKeys<PublicKey, SharedSecretKey> {
    /// The full accordant spend public key.
    pub public_spend_key: PublicKey,
    /// A list of extra accordant public keys.
    pub extra_public_keys: Vec<TaggedElement<u16, PublicKey>>,
    /// A list of secret shared keys, e.g. shared view keys in non-transparent blockchains.
    pub shared_secret_keys: Vec<TaggedElement<SharedKeyId, SharedSecretKey>>,
}

/// The full set of all keys related to the accordant blockchain available after the reveal round.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccordantKeySet<PublicKey, SharedSecretKey> {
    /// Alice's accordant keys (secret and public).
    pub alice: AccordantKeys<PublicKey, SharedSecretKey>,
    /// Bob's accordant keys (secret and public).
    pub bob: AccordantKeys<PublicKey, SharedSecretKey>,
}

fixed_hash::construct_fixed_hash!(
    /// Result of a keccak256 commitment.
    #[derive(Serialize, Deserialize)]
    pub struct KeccakCommitment(32);
);

impl KeccakCommitment {
    /// Create a null commitment hash with all zeros.
    pub fn null_hash() -> Self {
        Self([0u8; 32])
    }

    /// Hash a stream of bytes with the Keccak-256 hash function.
    pub fn new(input: [u8; 32]) -> Self {
        Self(input)
    }
}

impl CanonicalBytes for KeccakCommitment {
    fn as_canonical_bytes(&self) -> Vec<u8> {
        (*self).to_fixed_bytes().into()
    }

    fn from_canonical_bytes(bytes: &[u8]) -> Result<Self, consensus::Error>
    where
        Self: Sized,
    {
        Ok(Self::new(bytes.try_into().map_err(consensus::Error::new)?))
    }
}

/// Engine to produce and validate hash commitments.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
#[display(Debug)]
pub struct CommitmentEngine;

impl Commit<KeccakCommitment> for CommitmentEngine {
    fn commit_to<T: AsRef<[u8]>>(&self, value: T) -> KeccakCommitment {
        let mut out = [0u8; 32];
        let mut keccak = Keccak::v256();
        keccak.update(value.as_ref());
        keccak.finalize(&mut out);
        KeccakCommitment::new(out)
    }
}

/// Required for arbitrating and accordant blockchains to dervice extra public keys (keys not
/// automatically derives by the protocol by default) and extra shared private keys. Shared private
/// keys are used in situation when e.g. blockchain is not transparent or when extra nonces should
/// be exchanged.
///
/// ```
/// use farcaster_core::crypto::DeriveKeys;
/// use farcaster_core::crypto::SharedKeyId;
/// use bitcoin::secp256k1::{PublicKey, SecretKey};
///
/// pub struct Bitcoin;
///
/// impl DeriveKeys for Bitcoin {
///     type PublicKey = PublicKey;
///     type PrivateKey = SecretKey;
///
///     fn extra_public_keys() -> Vec<u16> {
///         // no extra needed
///         vec![]
///     }
///
///     fn extra_shared_private_keys() -> Vec<SharedKeyId> {
///         // no shared key needed, transparent blockchain
///         vec![]
///     }
/// }
/// ```
pub trait DeriveKeys {
    type PublicKey;
    type PrivateKey;

    /// Return a list of extra public key identifiers to use during the setup phase.
    fn extra_public_keys() -> Vec<u16>;

    /// Return a list of extra shared secret key identifiers to use during the setup phase.
    fn extra_shared_private_keys() -> Vec<SharedKeyId>;
}

/// Meta trait regrouping all the needed trait combinations a key manager must implement to manage
/// all the keys needed when executing the protocol on [`Alice`] and [`Bob`] methods. This trait is
/// auto-implemented for all `T` meeting the requirements.
///
/// [`Alice`]: crate::protocol::Alice
/// [`Bob`]: crate::protocol::Bob
pub trait KeyGenerator<ArPublicKey, AcPublicKey, ArSharedKey, AcSharedKey, Proof>:
    GenerateKey<ArPublicKey, ArbitratingKeyId>
    + GenerateKey<AcPublicKey, AccordantKeyId>
    + ProveCrossGroupDleq<ArPublicKey, AcPublicKey, Proof>
    + GenerateSharedKey<ArSharedKey>
    + GenerateSharedKey<AcSharedKey>
{
}

impl<T, ArPublicKey, AcPublicKey, ArSharedKey, AcSharedKey, Proof>
    KeyGenerator<ArPublicKey, AcPublicKey, ArSharedKey, AcSharedKey, Proof> for T
where
    T: GenerateKey<ArPublicKey, ArbitratingKeyId>
        + GenerateKey<AcPublicKey, AccordantKeyId>
        + GenerateSharedKey<ArSharedKey>
        + GenerateSharedKey<AcSharedKey>
        + ProveCrossGroupDleq<ArPublicKey, AcPublicKey, Proof>,
{
}

/// Public key generator. Generic interface over `PublicKey`, the public key type, and `KeyId`, the
/// identifier, used to retreive public keys by their identifiers.
pub trait GenerateKey<PublicKey, KeyId> {
    /// Retreive a specific public key by its key id. If the key cannot be derived the
    /// implementation must return an [`Error::UnsupportedKey`], otherwise `Ok(PublicKey)` is
    /// returned.
    fn get_pubkey(&mut self, key_id: KeyId) -> Result<PublicKey, Error>;

    /// Return a vector of public keys matching the vector of key ids. Errors on the first key that
    /// can't be derived and return an [`Error::UnsupportedKey`].
    fn get_pubkeys(&mut self, key_ids: Vec<KeyId>) -> Result<Vec<PublicKey>, Error> {
        key_ids.into_iter().map(|id| self.get_pubkey(id)).collect()
    }
}

/// Private shared key generator. Generic interface over `SharedKey`, the private key type, used to
/// retreive private shared keys by their identifiers: [`SharedKeyId`].
pub trait GenerateSharedKey<SharedKey> {
    /// Retreive a specific shared private key by its key id. If the key cannot be derived the
    /// implementation must return an [`Error::UnsupportedKey`].
    fn get_shared_key(&mut self, key_id: SharedKeyId) -> Result<SharedKey, Error>;
}

// TODO give extra keys and/or shared keys in signing methods

/// Signature generator and verifier. Produce and verify signatures based on public keys/key
/// identifiers.
pub trait Sign<PublicKey, Message, Signature> {
    /// Sign the message with the corresponding private key identified by the provided arbitrating
    /// key identifier.
    fn sign(&mut self, key: ArbitratingKeyId, msg: Message) -> Result<Signature, Error>;

    /// Verify a signature for a given message with the provided public key.
    fn verify_signature(&self, key: &PublicKey, msg: Message, sig: &Signature)
        -> Result<(), Error>;
}

/// Encrypted signature generator and verifier. Produce and verify encrypted sigantures based on
/// public keys/key identifiers.  Decrypt encrypted signature through key identifier to recover
/// signature.
pub trait EncSign<PublicKey, Message, Signature, EncryptedSignature> {
    /// Sign the message with the corresponding private key identified by the provided arbitrating
    /// key identifier and encrypt it (create an adaptor signature) with the provided encryption
    /// public key.
    fn encrypt_sign(
        &mut self,
        signing_key: ArbitratingKeyId,
        encryption_key: &PublicKey,
        msg: Message,
    ) -> Result<EncryptedSignature, Error>;

    /// Verify an encrypted signature for a given message with the provided signing public key and
    /// the public encryption key.
    fn verify_encrypted_signature(
        &self,
        signing_key: &PublicKey,
        encryption_key: &PublicKey,
        msg: Message,
        sig: &EncryptedSignature,
    ) -> Result<(), Error>;

    /// Decrypt the encrypted signature with the corresponding decryption private key identified by
    /// the provided accordant key identifier, producing a valid regular signature.
    fn decrypt_signature(
        &mut self,
        decryption_key: AccordantKeyId,
        sig: EncryptedSignature,
    ) -> Result<Signature, Error>;
}

/// Recover the secret key through the complete encrypted/decrypted signature and public
/// encryption key.
pub trait RecoverSecret<PublicKey, SecretKey, Signature, EncryptedSignature> {
    /// Recover the encryption key based on the encrypted signature, the encryption public key, and
    /// the regular (decrypted) signature.
    fn recover_secret_key(
        &self,
        encrypted_sig: EncryptedSignature,
        encryption_key: &PublicKey,
        sig: Signature,
    ) -> SecretKey;
}

/// Commitment generator and verifier. Generated commitments can be validated against candidates,
/// if correct the commit/reveal process is validated.
pub trait Commit<Commitment> {
    /// Provides a generic method to commit to any value referencable as stream of bytes.
    fn commit_to<T: AsRef<[u8]>>(&self, value: T) -> Commitment;

    /// Validate the equality between a candidate and a commitment, return `Ok(())` if the value
    /// commits to the same commitment's candidate, return [`Error::InvalidCommitment`]
    /// otherwise.
    fn validate<T: AsRef<[u8]>>(&self, candidate: T, commitment: Commitment) -> Result<(), Error>
    where
        Commitment: Eq,
    {
        if self.commit_to(candidate) == commitment {
            Ok(())
        } else {
            Err(Error::InvalidCommitment)
        }
    }
}

/// Proof generator and verifier for the cross-group projection of the accordant public spend key
/// as an arbitrating key used to encrypt signatures.
pub trait ProveCrossGroupDleq<EncryptionKey, AccordantSpendKey, Proof> {
    /// Generate the proof and the two public keys: the accordant public spend key and the
    /// arbitrating public key, also called the encryption public key,
    fn generate_proof(&mut self) -> Result<(AccordantSpendKey, EncryptionKey, Proof), Error>;

    /// Project the accordant spend secret key over the arbitrating curve to get the public key
    /// used as the encryption public key.
    fn get_encryption_key(&mut self) -> Result<EncryptionKey, Error>;

    /// Verify the proof given the two public keys: the accordant spend public key and the
    /// arbitrating encryption public key.
    fn verify_proof(
        &mut self,
        public_spend: &AccordantSpendKey,
        encryption_key: &EncryptionKey,
        proof: Proof,
    ) -> Result<(), Error>;
}