profile
viewpoint

daira/curvesearch 18

Elliptic curve search experiments

daira/describe-curve 17

Describe elliptic curves

daira/halographs 15

Slides and notes for "Halo Optimizations and Constructing Graphs of Elliptic Curves"

daira/jubjub 12

Supporting evidence for security of the Jubjub curve to be used in Zcash

boltlabs-inc/zkchannels-spec 2

specifications of the blockchain interaction for zkchannels

daira/dualpowsim 1

Undocumented Python 3 programs for simulating dual PoW and confirmation times for Zcash. Please report issues at https://github.com/zcash/zcash/issues

daira/librustzcash 1

Rust-language assets for Zcash

daira/algebra 0

Libraries for finite field, elliptic curve, and polynomial arithmetic

daira/api-guidelines 0

Rust API guidelines

daira/bellman 0

zk-SNARK library.

PullRequestReviewEvent
PullRequestReviewEvent
PullRequestReviewEvent
PullRequestReviewEvent

issue openedzcash/halo2

[Book] Document the selector combining optimization

Transfer https://hackmd.io/@daira/SkjDVkLCd (view only) to the book.

created time in 17 hours

pull request commentzcash/librustzcash

Add auto-shielding to the data access API

This branch cannot target master anymore, because we merged the ZIP 244 consensus changes to that branch, and we need this to be in a branch that is usable by zcashd in v4.7.0-rc1, prior to merging the changes that alter the NU5 consensus rules.

That means we have to release v4.7.0-rc1 from a branch other than master, right? Should we create that branch now?

nuttycom

comment created time in a day

Pull request review commentzcash/librustzcash

Add auto-shielding to the data access API

 impl Payment { /// payment value in the request. #[derive(Debug, PartialEq)] pub struct TransactionRequest {-    payments: Vec<Payment>,+    pub payments: Vec<Payment>,

More than 2108 payments, since one Output is needed for change. Anyway, we should probably impose a lower limit than that; 2 Mbyte transactions are not particularly friendly.

nuttycom

comment created time in a day

PullRequestReviewEvent

issue commentzcash/zcash

Introduce standardized t+z-addr encoding.

This is what Unified Addresses are, modulo not being implemented via Payment URIs. Do we still need this ticket?

nathan-at-least

comment created time in a day

PullRequestReviewEvent

Pull request review commentzcash/librustzcash

[ZIP 316] Transparent internal and external ovk

+use crate::sapling::keys::{prf_expand_vec, OutgoingViewingKey as SaplingOvk};+use crate::zip32::ChainCode;+use std::convert::TryInto;+use zcash_address::unified::{Container, Fvk, Ufvk};++/// The transparent full viewing key as specified in [ZIP 316][transparent-fvk].+///+/// [transparent-fvk]: https://zips.z.cash/zip-0316#encoding-of-unified-full-incoming-viewing-keys+pub struct FullViewingKey {+    c: ChainCode,+    pk: secp256k1::PublicKey,+}++/// Internal ovk used for autoshielding.+pub struct InternalOvk([u8; 32]);++impl InternalOvk {+    pub fn as_bytes(&self) -> [u8; 32] {+        self.0+    }+}++/// External ovk used by zcashd for transparent -> shielded spends to+/// external receivers.+pub struct ExternalOvk([u8; 32]);++impl ExternalOvk {+    pub fn as_bytes(&self) -> [u8; 32] {+        self.0+    }+}++impl FullViewingKey {+    /// Derives the internal ovk and external ovk corresponding to this+    /// transparent fvk. As specified in [ZIP 316][transparent-ovk].+    ///+    /// [transparent-ovk]: https://zips.z.cash/zip-0316#deriving-internal-keys+    fn ovk_for_shielding(&self) -> (InternalOvk, ExternalOvk) {+        let i_ovk = prf_expand_vec(&self.c.as_bytes(), &[&[0xd0], &self.pk.serialize()]);+        let i_ovk = i_ovk.as_bytes();+        let ovk_internal = InternalOvk(i_ovk[..32].try_into().unwrap());+        let ovk_external = ExternalOvk(i_ovk[32..].try_into().unwrap());++        (ovk_internal, ovk_external)+    }++    /// Derives the internal ovk corresponding to this transparent fvk.+    pub fn internal_ovk(&self) -> InternalOvk {+        self.ovk_for_shielding().0+    }++    /// Derives the external ovk corresponding to this transparent fvk.+    pub fn external_ovk(&self) -> ExternalOvk {+        self.ovk_for_shielding().1+    }+}++impl From<(ChainCode, secp256k1::PublicKey)> for FullViewingKey {+    fn from(c_pk: (ChainCode, secp256k1::PublicKey)) -> FullViewingKey {+        FullViewingKey {+            c: c_pk.0,+            pk: c_pk.1,+        }+    }+}++impl std::convert::TryFrom<[u8; 65]> for FullViewingKey {+    type Error = secp256k1::Error;+    fn try_from(bytes: [u8; 65]) -> Result<Self, Self::Error> {+        let c: [u8; 32] = bytes[..32].try_into().unwrap();+        let c: ChainCode = c.into();+        let pk = secp256k1::PublicKey::from_slice(&bytes[32..])?;+        Ok((c, pk).into())+    }+}++/// A transparent internal ovk can be used to shield to Sapling.+impl From<InternalOvk> for SaplingOvk {+    fn from(t_int_ovk: InternalOvk) -> SaplingOvk {+        SaplingOvk(t_int_ovk.0)+    }+}++/// Finds the internal or external ovk for the transparent component+/// of a given Ufvk, if it exists.+pub fn find_ovk(key: &Ufvk, external: bool) -> Option<[u8; 32]> {+    for r in &key.items() {+        if let Fvk::P2pkh(data) = r {+            let fvk: FullViewingKey = (*data).try_into().ok()?;

Oh it's just because the TryInto implementation above fills in the gap.

therealyingtong

comment created time in a day

PullRequestReviewEvent

Pull request review commentzcash/librustzcash

[ZIP 316] Transparent internal and external ovk

 where         .get_target_and_anchor_heights(min_confirmations)         .and_then(|x| x.ok_or_else(|| Error::ScanRequired.into()))?; -    // derive the corresponding t-address+    // derive the corresponding transparent internal ovk+    let t_fvk: transparent::FullViewingKey = {+        let secp = secp256k1::Secp256k1::new();+        let pk = secp256k1::PublicKey::from_secret_key(&secp, sk);+        (extfvk.chain_code(), pk).into()

Add a TODO and/or use a chain code that is obviously wrong, like all-zeros, for now.

therealyingtong

comment created time in a day

PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commentzcash/librustzcash

[ZIP 316] Transparent internal and external ovk

+use crate::sapling::keys::{prf_expand_vec, OutgoingViewingKey as SaplingOvk};+use crate::zip32::ChainCode;+use std::convert::TryInto;+use zcash_address::unified::{Container, Fvk, Ufvk};++/// The transparent full viewing key as specified in [ZIP 316][transparent-fvk].+///+/// [transparent-fvk]: https://zips.z.cash/zip-0316#encoding-of-unified-full-incoming-viewing-keys+pub struct FullViewingKey {+    c: ChainCode,+    pk: secp256k1::PublicKey,+}++/// Internal ovk used for autoshielding.+pub struct InternalOvk([u8; 32]);++impl InternalOvk {+    pub fn as_bytes(&self) -> [u8; 32] {+        self.0+    }+}++/// External ovk used by zcashd for transparent -> shielded spends to+/// external receivers.+pub struct ExternalOvk([u8; 32]);++impl ExternalOvk {+    pub fn as_bytes(&self) -> [u8; 32] {+        self.0+    }+}++impl FullViewingKey {+    /// Derives the internal ovk and external ovk corresponding to this+    /// transparent fvk. As specified in [ZIP 316][transparent-ovk].+    ///+    /// [transparent-ovk]: https://zips.z.cash/zip-0316#deriving-internal-keys+    fn ovk_for_shielding(&self) -> (InternalOvk, ExternalOvk) {+        let i_ovk = prf_expand_vec(&self.c.as_bytes(), &[&[0xd0], &self.pk.serialize()]);+        let i_ovk = i_ovk.as_bytes();+        let ovk_internal = InternalOvk(i_ovk[..32].try_into().unwrap());+        let ovk_external = ExternalOvk(i_ovk[32..].try_into().unwrap());++        (ovk_internal, ovk_external)+    }++    /// Derives the internal ovk corresponding to this transparent fvk.+    pub fn internal_ovk(&self) -> InternalOvk {+        self.ovk_for_shielding().0+    }++    /// Derives the external ovk corresponding to this transparent fvk.+    pub fn external_ovk(&self) -> ExternalOvk {+        self.ovk_for_shielding().1+    }+}++impl From<(ChainCode, secp256k1::PublicKey)> for FullViewingKey {+    fn from(c_pk: (ChainCode, secp256k1::PublicKey)) -> FullViewingKey {+        FullViewingKey {+            c: c_pk.0,+            pk: c_pk.1,+        }+    }+}++impl std::convert::TryFrom<[u8; 65]> for FullViewingKey {+    type Error = secp256k1::Error;+    fn try_from(bytes: [u8; 65]) -> Result<Self, Self::Error> {+        let c: [u8; 32] = bytes[..32].try_into().unwrap();+        let c: ChainCode = c.into();+        let pk = secp256k1::PublicKey::from_slice(&bytes[32..])?;+        Ok((c, pk).into())+    }+}++/// A transparent internal ovk can be used to shield to Sapling.+impl From<InternalOvk> for SaplingOvk {+    fn from(t_int_ovk: InternalOvk) -> SaplingOvk {+        SaplingOvk(t_int_ovk.0)+    }+}++/// Finds the internal or external ovk for the transparent component+/// of a given Ufvk, if it exists.+pub fn find_ovk(key: &Ufvk, external: bool) -> Option<[u8; 32]> {+    for r in &key.items() {+        if let Fvk::P2pkh(data) = r {+            let fvk: FullViewingKey = (*data).try_into().ok()?;

This is similar but different to https://github.com/zcash/zcash/pull/5470/files#diff-98a0abefb7ae486bd76f5e8d28d7fd65cead55c7344b31cc90caa56583917ca3R155-R159 . Why the difference?

therealyingtong

comment created time in a day

PullRequestReviewEvent

Pull request review commentzcash/zcash

ZIP 316: Transparent ovk

 pub extern "C" fn unified_full_viewing_key_from_components(         }     } }++/// Selects a preferred ovk given input notes from multiple different pools+/// from the same unified full viewing key.+#[no_mangle]+pub extern "C" fn unified_full_viewing_key_preferred_ovk(key: *const Ufvk, out: *mut [u8; 32]) {+    todo!()+}++/// Derives an outgoing viewing key from a transparent full viewing key.+#[no_mangle]+pub extern "C" fn unified_full_viewing_key_transparent_ovk(+    key: *const Ufvk,+    external: bool,+    out: *mut [u8; 32],+) -> bool {+    let key = unsafe { key.as_ref() }.expect("Unified full viewing key pointer may not be null.");+    let out = unsafe { &mut *out };++    for r in &key.items() {+        if let Fvk::P2pkh(data) = r {+            let c: [u8; 32] = data[0..32].try_into().unwrap();+            let c: ChainCode = c.into();+            let pk =+                secp256k1::PublicKey::from_slice(&data[32..]).expect("pk is already validated.");+            let fvk: transparent::FullViewingKey = (c, pk).into();++            if external {+                *out = fvk.external_ovk().as_bytes();+            } else {+                *out = fvk.internal_ovk().as_bytes();+            }++            return true;+        }+    }++    false

Use find_ovk defined at https://github.com/zcash/librustzcash/pull/480/files#diff-3b307a8fabc1b1ac923d7b23188c2fd995a416495c210a148a9914e7728d503aR86

    if let Some(ovk) = find_ovk(key, external) {
        *out = ovk.as_bytes();
        true
    } else {
        *out = [0; 32];
        false
    }

(I'm not sure if *out = [0; 32]; is correct. In any case, zeroing the output array on error is probably a good idea.)

therealyingtong

comment created time in a day

PullRequestReviewEvent

issue commentzcash/zcash

Define a coordinated disclosure policy for security flaws

We have a coordinated disclosure process which is documented in https://github.com/zcash/zcash/blob/master/SECURITY.md . It's not linked from https://z.cash/support/security/ as I would expect, though.

daira

comment created time in 2 days

issue commentzcash/zcash

Write security proofs for nonstandard primitives

Just to tie up a few loose ends:

  • If you want a conservatively secure PRF or CRPRF or KDF that does not need to be especially circuit-efficient for a new design, use a hash with a keyed mode like BLAKE2b/s or BLAKE3. The reason for using SHA-256 was that we already had an implementation of it, but not of BLAKE2s, in the circuit at the time. (BLAKE2s was added for CRH<sup>ivk</sup> in the Sapling circuit.) BLAKE2s and BLAKE3 are smaller than SHA-256 in a circuit.
  • You can alternatively assume that SHA256Compress is free-start collision-resistant (i.e. collision-resistant on an input that also includes the chaining variable), in order to prove that NoteCommit<sup>Sprout</sup> is binding. The assumption that COMM' is binding is weaker; it's essentially the same problem but the adversary must use a random r rather than chosen r.
defuse

comment created time in 2 days

PullRequestReviewEvent
PullRequestReviewEvent
PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commentzcash/zcash

allow UA as z_shieldcoinbase destination

 UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)                 }             },             [&](const libzcash::UnifiedAddress& ua) {-                throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a unified address.");+                if (!Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_NU5)) {+                    throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a unified address.");

This is confusing though. Specifying a UA shouldn't require NU5; only shielding to an Orchard address should require NU5.

LarryRuane

comment created time in 2 days

PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commentzcash/zcash

allow UA as z_shieldcoinbase destination

 UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)                 }             },             [&](const libzcash::UnifiedAddress& ua) {-                throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a unified address.");+                if (!Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_NU5)) {+                    throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a unified address.");
                    throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a unified address because NU5 is not active in the next block.");
LarryRuane

comment created time in 2 days

more