Przeglądaj źródła

crypto: Fix up tests and move types to crate root.

parazyd 4 lat temu
rodzic
commit
b05e05df7b

+ 38 - 0
Cargo.lock

@@ -292,6 +292,17 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a"
 
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
 [[package]]
 name = "autocfg"
 version = "1.0.1"
@@ -541,6 +552,17 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
 
+[[package]]
+name = "colored"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59"
+dependencies = [
+ "atty",
+ "lazy_static",
+ "winapi",
+]
+
 [[package]]
 name = "concurrent-queue"
 version = "1.2.2"
@@ -806,6 +828,7 @@ dependencies = [
 name = "darkfi"
 version = "0.2.0"
 dependencies = [
+ "arrayvec 0.7.2",
  "async-channel",
  "async-executor",
  "async-native-tls",
@@ -825,12 +848,14 @@ dependencies = [
  "log",
  "native-tls",
  "num-bigint",
+ "num_cpus",
  "pasta_curves",
  "rand 0.8.4",
  "rocksdb",
  "rusqlite",
  "serde",
  "serde_json",
+ "simple_logger",
  "smol",
  "toml",
  "tungstenite",
@@ -2422,6 +2447,19 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "simple_logger"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7de33c687404ec3045d4a0d437580455257c0436f858d702f244e7d652f9f07"
+dependencies = [
+ "atty",
+ "chrono",
+ "colored",
+ "log",
+ "winapi",
+]
+
 [[package]]
 name = "slab"
 version = "0.4.5"

+ 3 - 0
Cargo.toml

@@ -34,6 +34,7 @@ blake2b_simd = "0.5.11"
 blake2s_simd = "0.5.11"
 group = "0.11.0"
 crypto_api_chachapoly = "0.5.0"
+arrayvec = "0.7.0"
 
 hex = "0.4.3"
 bs58 = "0.4.0"
@@ -52,6 +53,8 @@ futures = "0.3.17"
 smol = "1.2.5"
 
 log = "0.4.14"
+simple_logger = "1.13.0"
+num_cpus = "1.13.0"
 
 lazy_static = "1.4.0"
 

+ 0 - 1
src/bin/darkfid.rs

@@ -1,6 +1,5 @@
 use async_std::sync::{Arc, Mutex};
 use std::collections::HashMap;
-use std::convert::TryInto;
 use std::path::PathBuf;
 use std::str::FromStr;
 

+ 140 - 0
src/crypto/constants/fixed_bases.rs

@@ -1,8 +1,13 @@
+use arrayvec::ArrayVec;
 use halo2_gadgets::ecc::{
     chip::{compute_lagrange_coeffs, NUM_WINDOWS, NUM_WINDOWS_SHORT},
     FixedPoints, H,
 };
 use pasta_curves::pallas;
+use pasta_curves::{
+    arithmetic::{CurveAffine, Field, FieldExt},
+    group::Curve,
+};
 
 pub mod commit_ivk_r;
 pub mod note_commit_r;
@@ -20,6 +25,19 @@ pub const VALUE_COMMITMENT_R_BYTES: [u8; 1] = *b"r";
 /// SWU hash-to-curve value for the value commitment generator
 pub const VALUE_COMMITMENT_V_BYTES: [u8; 1] = *b"v";
 
+/// SWU hash-to-curve personalization for the note commitment generator
+pub const NOTE_COMMITMENT_PERSONALIZATION: &str = "z.cash:Orchard-NoteCommit";
+
+/// SWU hash-to-curve personalization for the IVK commitment generator
+pub const COMMIT_IVK_PERSONALIZATION: &str = "z.cash:Orchard-CommitIvk";
+
+/// SWU hash-to-curve personalization for the spending key base point and
+/// the nullifier base point K^Orchard
+pub const ORCHARD_PERSONALIZATION: &str = "z.cash:Orchard";
+
+/// Window size for fixed-base scalar multiplication
+pub const FIXED_BASE_WINDOW_SIZE: usize = 3;
+
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum OrchardFixedBases {
     CommitIvkR,
@@ -72,3 +90,125 @@ impl FixedPoints<pallas::Affine> for OrchardFixedBases {
         }
     }
 }
+
+/// For each fixed base, we calculate its scalar multiples in three-bit windows.
+/// Each window will have $2^3 = 8$ points.
+#[allow(dead_code)]
+fn compute_window_table<C: CurveAffine>(base: C, num_windows: usize) -> Vec<[C; H]> {
+    let mut window_table: Vec<[C; H]> = Vec::with_capacity(num_windows);
+
+    // Generate window table entries for all windows but the last.
+    // For these first `num_windows - 1` windows, we compute the multiple [(k+2)*(2^3)^w]B.
+    // Here, w ranges from [0..`num_windows - 1`)
+    for w in 0..(num_windows - 1) {
+        window_table.push(
+            (0..H)
+                .map(|k| {
+                    // scalar = (k+2)*(8^w)
+                    let scalar = C::ScalarExt::from_u64(k as u64 + 2)
+                        * C::ScalarExt::from_u64(H as u64).pow(&[w as u64, 0, 0, 0]);
+                    (base * scalar).to_affine()
+                })
+                .collect::<ArrayVec<C, H>>()
+                .into_inner()
+                .unwrap(),
+        );
+    }
+
+    // Generate window table entries for the last window, w = `num_windows - 1`.
+    // For the last window, we compute [k * (2^3)^w - sum]B, where sum is defined
+    // as sum = \sum_{j = 0}^{`num_windows - 2`} 2^{3j+1}
+    let sum = (0..(num_windows - 1)).fold(C::ScalarExt::zero(), |acc, j| {
+        acc + C::ScalarExt::from_u64(2).pow(&[
+            FIXED_BASE_WINDOW_SIZE as u64 * j as u64 + 1,
+            0,
+            0,
+            0,
+        ])
+    });
+    window_table.push(
+        (0..H)
+            .map(|k| {
+                // scalar = k * (2^3)^w - sum, where w = `num_windows - 1`
+                let scalar = C::ScalarExt::from_u64(k as u64)
+                    * C::ScalarExt::from_u64(H as u64).pow(&[(num_windows - 1) as u64, 0, 0, 0])
+                    - sum;
+                (base * scalar).to_affine()
+            })
+            .collect::<ArrayVec<C, H>>()
+            .into_inner()
+            .unwrap(),
+    );
+
+    window_table
+}
+
+#[cfg(test)]
+// Test that Lagrange interpolation coefficients reproduce the correct x-coordinate
+// for each fixed-base multiple in each window.
+fn test_lagrange_coeffs<C: CurveAffine>(base: C, num_windows: usize) {
+    let lagrange_coeffs = compute_lagrange_coeffs(base, num_windows);
+
+    // Check first 84 windows, i.e. `k_0, k_1, ..., k_83`
+    for (idx, coeffs) in lagrange_coeffs[0..(num_windows - 1)].iter().enumerate() {
+        // Test each three-bit chunk in this window.
+        for bits in 0..(1 << FIXED_BASE_WINDOW_SIZE) {
+            {
+                // Interpolate the x-coordinate using this window's coefficients
+                let interpolated_x = super::util::evaluate::<C>(bits, coeffs);
+
+                // Compute the actual x-coordinate of the multiple [(k+2)*(8^w)]B.
+                let point = base
+                    * C::Scalar::from_u64(bits as u64 + 2)
+                    * C::Scalar::from_u64(H as u64).pow(&[idx as u64, 0, 0, 0]);
+                let x = *point.to_affine().coordinates().unwrap().x();
+
+                // Check that the interpolated x-coordinate matches the actual one.
+                assert_eq!(x, interpolated_x);
+            }
+        }
+    }
+
+    // Check last window.
+    for bits in 0..(1 << FIXED_BASE_WINDOW_SIZE) {
+        // Interpolate the x-coordinate using the last window's coefficients
+        let interpolated_x = super::util::evaluate::<C>(bits, &lagrange_coeffs[num_windows - 1]);
+
+        // Compute the actual x-coordinate of the multiple [k * (8^84) - offset]B,
+        // where offset = \sum_{j = 0}^{83} 2^{3j+1}
+        let offset = (0..(num_windows - 1)).fold(C::Scalar::zero(), |acc, w| {
+            acc + C::Scalar::from_u64(2).pow(&[
+                FIXED_BASE_WINDOW_SIZE as u64 * w as u64 + 1,
+                0,
+                0,
+                0,
+            ])
+        });
+        let scalar = C::Scalar::from_u64(bits as u64)
+            * C::Scalar::from_u64(H as u64).pow(&[(num_windows - 1) as u64, 0, 0, 0])
+            - offset;
+        let point = base * scalar;
+        let x = *point.to_affine().coordinates().unwrap().x();
+
+        // Check that the interpolated x-coordinate matches the actual one.
+        assert_eq!(x, interpolated_x);
+    }
+}
+
+#[cfg(test)]
+// Test that the z-values and u-values satisfy the conditions:
+//      1. z + y = u^2,
+//      2. z - y is not a square
+// for the y-coordinate of each fixed-base multiple in each window.
+fn test_zs_and_us<C: CurveAffine>(base: C, z: &[u64], u: &[[[u8; 32]; H]], num_windows: usize) {
+    let window_table = compute_window_table(base, num_windows);
+
+    for ((u, z), window_points) in u.iter().zip(z.iter()).zip(window_table) {
+        for (u, point) in u.iter().zip(window_points.iter()) {
+            let y = *point.coordinates().unwrap().y();
+            let u = C::Base::from_bytes(u).unwrap();
+            assert_eq!(C::Base::from_u64(*z) + y, u * u); // allow either square root
+            assert!(bool::from((C::Base::from_u64(*z) - y).sqrt().is_none()));
+        }
+    }
+}

+ 13 - 11
src/crypto/constants/sinsemilla.rs

@@ -21,9 +21,6 @@ pub const INV_TWO_POW_K: [u8; 32] = [
 /// of Pallas.
 pub const C: usize = 253;
 
-/// $\ell^\mathsf{Orchard}_\mathsf{Merkle}$
-//pub(crate) const L_ORCHARD_MERKLE: usize = 255;
-
 /// SWU hash-to-curve personalization for the Merkle CRH generator
 pub const MERKLE_CRH_PERSONALIZATION: &str = "z.cash:Orchard-MerkleCRH";
 
@@ -73,8 +70,14 @@ pub const Q_MERKLE_CRH: ([u8; 32], [u8; 32]) = (
     ],
 );
 
-/*
-pub(crate) fn lebs2ip_k(bits: &[bool]) -> u32 {
+#[allow(dead_code)]
+fn i2lebsp<const NUM_BITS: usize>(int: u64) -> [bool; NUM_BITS] {
+    assert!(NUM_BITS <= 64);
+    super::util::gen_const_array(|mask: usize| (int & (1 << mask)) != 0)
+}
+
+#[allow(dead_code)]
+fn lebs2ip_k(bits: &[bool]) -> u32 {
     assert!(bits.len() == K);
     bits.iter()
         .enumerate()
@@ -83,11 +86,11 @@ pub(crate) fn lebs2ip_k(bits: &[bool]) -> u32 {
 
 /// The sequence of K bits in little-endian order representing an integer
 /// up to `2^K` - 1.
-pub(crate) fn i2lebsp_k(int: usize) -> [bool; K] {
+#[allow(dead_code)]
+fn i2lebsp_k(int: usize) -> [bool; K] {
     assert!(int < (1 << K));
     i2lebsp(int as u64)
 }
-*/
 
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub enum OrchardHashDomains {
@@ -144,16 +147,15 @@ impl CommitDomains<pallas::Affine, OrchardFixedBases, OrchardHashDomains> for Or
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::constants::{
+    use crate::crypto::constants::{
         fixed_bases::{COMMIT_IVK_PERSONALIZATION, NOTE_COMMITMENT_PERSONALIZATION},
         sinsemilla::MERKLE_CRH_PERSONALIZATION,
     };
     use halo2_gadgets::primitives::sinsemilla::{CommitDomain, HashDomain};
 
-    use ff::PrimeField;
-    use group::Curve;
     use pasta_curves::{
         arithmetic::{CurveAffine, FieldExt},
+        group::{ff::PrimeField, Curve},
         pallas,
     };
     use rand::{self, rngs::OsRng, Rng};
@@ -161,7 +163,7 @@ mod tests {
     #[test]
     // Nodes in the Merkle tree are Pallas base field elements.
     fn l_orchard_merkle() {
-        assert_eq!(super::L_ORCHARD_MERKLE, pallas::Base::NUM_BITS as usize);
+        assert_eq!(255, pallas::Base::NUM_BITS as usize);
     }
 
     #[test]

+ 6 - 4
src/crypto/mint_proof.rs

@@ -11,12 +11,14 @@ use pasta_curves::{
 
 use super::{
     proof::{Proof, ProvingKey, VerifyingKey},
-    types::*,
     util::{mod_r_p, pedersen_commitment_scalar, pedersen_commitment_u64},
 };
-use crate::circuit::mint_contract::MintContract;
-use crate::error::Result;
-use crate::serial::{Decodable, Encodable};
+use crate::{
+    circuit::mint_contract::MintContract,
+    serial::{Decodable, Encodable},
+    types::*,
+    Result,
+};
 
 pub struct MintRevealedValues {
     pub value_commit: DrkValueCommit,

+ 5 - 4
src/crypto/mod.rs

@@ -8,16 +8,17 @@ pub mod pasta_serial;
 pub mod proof;
 pub mod schnorr;
 pub mod spend_proof;
-pub mod types;
 pub mod util;
 
+use crate::types::*;
+
 #[derive(Clone)]
 pub struct OwnCoin {
-    pub coin: types::DrkCoin,
+    pub coin: DrkCoin,
     pub note: note::Note,
-    pub secret: types::DrkSecretKey,
+    pub secret: DrkSecretKey,
     //pub witness: merkle::IncrementalWitness<merkle_node::MerkleNode>,
-    pub nullifier: types::DrkNullifier,
+    pub nullifier: DrkNullifier,
 }
 
 pub type OwnCoins = Vec<OwnCoin>;

+ 13 - 9
src/crypto/note.rs

@@ -6,11 +6,13 @@ use rand::rngs::OsRng;
 
 use super::{
     diffie_hellman::{kdf_sapling, sapling_ka_agree},
-    types::*,
     util::mod_r_p,
 };
-use crate::error::{Error, Result};
-use crate::serial::{Decodable, Encodable, ReadExt, WriteExt};
+use crate::{
+    serial::{Decodable, Encodable, ReadExt, WriteExt},
+    types::*,
+    Error, Result,
+};
 
 pub const NOTE_PLAINTEXT_SIZE: usize = 32 +    // serial
     8 +     // value
@@ -129,16 +131,18 @@ impl EncryptedNote {
 
 #[test]
 fn test_note_encdec() {
+    use crate::types::*;
+
     let note = Note {
-        serial: jubjub::Fr::random(&mut OsRng),
+        serial: DrkSerial::random(&mut OsRng),
         value: 110,
-        token_id: jubjub::Fr::random(&mut OsRng),
-        coin_blind: jubjub::Fr::random(&mut OsRng),
-        valcom_blind: jubjub::Fr::random(&mut OsRng),
+        token_id: DrkTokenId::random(&mut OsRng),
+        coin_blind: DrkCoinBlind::random(&mut OsRng),
+        valcom_blind: DrkValueBlind::random(&mut OsRng),
     };
 
-    let secret = jubjub::Fr::random(&mut OsRng);
-    let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
+    let secret = DrkSecretKey::random(&mut OsRng);
+    let public = derive_publickey(secret);
 
     let encrypted_note = note.encrypt(&public).unwrap();
     let note2 = encrypted_note.decrypt(&secret).unwrap();

+ 4 - 2
src/crypto/pasta_serial.rs

@@ -3,8 +3,10 @@ use std::io;
 use pasta_curves as pasta;
 use pasta_curves::{arithmetic::FieldExt, group::GroupEncoding};
 
-use crate::error::{Error, Result};
-use crate::serial::{Decodable, Encodable, ReadExt, WriteExt};
+use crate::{
+    serial::{Decodable, Encodable, ReadExt, WriteExt},
+    Error, Result,
+};
 
 impl Encodable for pasta::Fp {
     fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {

+ 1 - 1
src/crypto/proof.rs

@@ -8,7 +8,7 @@ use halo2::{
     transcript::{Blake2bRead, Blake2bWrite},
 };
 
-use super::types::*;
+use crate::types::*;
 
 #[derive(Debug)]
 pub struct VerifyingKey {

+ 5 - 3
src/crypto/schnorr.rs

@@ -6,11 +6,13 @@ use rand::rngs::OsRng;
 
 use super::{
     constants::{OrchardFixedBases, DRK_SCHNORR_DOMAIN},
-    types::*,
     util::{hash_to_scalar, mod_r_p},
 };
-use crate::error::Result;
-use crate::serial::{Decodable, Encodable};
+use crate::{
+    serial::{Decodable, Encodable},
+    types::*,
+    Result,
+};
 
 pub struct SecretKey(pub DrkSecretKey);
 

+ 6 - 4
src/crypto/spend_proof.rs

@@ -13,12 +13,14 @@ use pasta_curves::{
 
 use super::{
     proof::{Proof, ProvingKey, VerifyingKey},
-    types::*,
     util::{mod_r_p, pedersen_commitment_scalar, pedersen_commitment_u64},
 };
-use crate::circuit::spend_contract::SpendContract;
-use crate::serial::{Decodable, Encodable};
-use crate::Result;
+use crate::{
+    circuit::spend_contract::SpendContract,
+    serial::{Decodable, Encodable},
+    types::*,
+    Result,
+};
 
 pub struct SpendRevealedValues {
     pub value_commit: DrkValueCommit,

+ 3 - 5
src/crypto/util.rs

@@ -5,12 +5,10 @@ use pasta_curves::{
     pallas,
 };
 
-use super::{
-    constants::fixed_bases::{
-        VALUE_COMMITMENT_PERSONALIZATION, VALUE_COMMITMENT_R_BYTES, VALUE_COMMITMENT_V_BYTES,
-    },
-    types::*,
+use super::constants::fixed_bases::{
+    VALUE_COMMITMENT_PERSONALIZATION, VALUE_COMMITMENT_R_BYTES, VALUE_COMMITMENT_V_BYTES,
 };
+use crate::types::*;
 
 pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> DrkScalar {
     let mut hasher = Params::new().hash_length(64).personal(persona).to_state();

+ 1 - 0
src/lib.rs

@@ -13,6 +13,7 @@ pub mod serial;
 // pub mod service;
 // pub mod state;
 pub mod system;
+pub mod types;
 // pub mod tx;
 // pub mod util;
 // pub mod vm;

+ 1 - 1
src/crypto/types.rs → src/types.rs

@@ -3,7 +3,7 @@
 use halo2_gadgets::ecc::FixedPoints;
 use pasta_curves as pasta;
 
-use super::{constants::OrchardFixedBases, util::mod_r_p};
+use crate::crypto::{constants::OrchardFixedBases, util::mod_r_p};
 
 pub type DrkCircuitField = pasta::Fp;