Skip to content
Merged
15 changes: 13 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
# See: https://circleci.com/docs/2.0/configuration-reference
version: 2.1

orbs:
slack: circleci/slack@4.1

# Define a job to be invoked later in a workflow.
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
jobs:
Expand All @@ -17,13 +20,21 @@ jobs:
- run:
name: "cargo test"
command: |
sudo apt update && sudo apt-get install libfontconfig libfontconfig1-dev libfreetype6-dev;
cargo version;
cargo test;
cargo test --all --all-features;
- slack/notify:
event: fail
template: basic_fail_1
- slack/notify:
event: pass
template: basic_success_1


# Invoke jobs via workflows
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
workflows:
build-and-test:
jobs:
- cargo-test
- cargo-test:
context: CI-Orchard-slack
7 changes: 5 additions & 2 deletions src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ pub(crate) mod testing {

use proptest::prelude::*;

use crate::note::NoteType;
use crate::{
note::{
commitment::ExtractedNoteCommitment, nullifier::testing::arb_nullifier,
Expand All @@ -150,7 +151,8 @@ pub(crate) mod testing {
let cmx = ExtractedNoteCommitment::from(note.commitment());
let cv_net = ValueCommitment::derive(
spend_value - output_value,
ValueCommitTrapdoor::zero()
ValueCommitTrapdoor::zero(),
NoteType::native()
);
// FIXME: make a real one from the note.
let encrypted_note = TransmittedNoteCiphertext {
Expand Down Expand Up @@ -181,7 +183,8 @@ pub(crate) mod testing {
let cmx = ExtractedNoteCommitment::from(note.commitment());
let cv_net = ValueCommitment::derive(
spend_value - output_value,
ValueCommitTrapdoor::zero()
ValueCommitTrapdoor::zero(),
NoteType::native()
);

// FIXME: make a real one from the note.
Expand Down
18 changes: 15 additions & 3 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use nonempty::NonEmpty;
use pasta_curves::pallas;
use rand::{prelude::SliceRandom, CryptoRng, RngCore};

use crate::note::NoteType;
use crate::{
action::Action,
address::Address,
Expand Down Expand Up @@ -140,7 +141,7 @@ impl ActionInfo {
/// [orchardsend]: https://zips.z.cash/protocol/nu5.pdf#orchardsend
fn build(self, mut rng: impl RngCore) -> (Action<SigningMetadata>, Circuit) {
let v_net = self.value_sum();
let cv_net = ValueCommitment::derive(v_net, self.rcv.clone());
let cv_net = ValueCommitment::derive(v_net, self.rcv, NoteType::native());

let nf_old = self.spend.note.nullifier(&self.spend.fvk);
let sender_address = self.spend.note.recipient();
Expand All @@ -150,8 +151,15 @@ impl ActionInfo {
let ak: SpendValidatingKey = self.spend.fvk.clone().into();
let alpha = pallas::Scalar::random(&mut rng);
let rk = ak.randomize(&alpha);
let note_type = self.spend.note.note_type();

let note = Note::new(self.output.recipient, self.output.value, nf_old, &mut rng);
let note = Note::new(
self.output.recipient,
self.output.value,
note_type,
nf_old,
&mut rng,
);
let cm_new = note.commitment();
let cmx = cm_new.into();

Expand Down Expand Up @@ -361,7 +369,11 @@ impl Builder {

// Verify that bsk and bvk are consistent.
let bvk = (actions.iter().map(|a| a.cv_net()).sum::<ValueCommitment>()
- ValueCommitment::derive(value_balance, ValueCommitTrapdoor::zero()))
- ValueCommitment::derive(
value_balance,
ValueCommitTrapdoor::zero(),
NoteType::native(),
))
.into_bvk();
assert_eq!(redpallas::VerificationKey::from(&bsk), bvk);

Expand Down
2 changes: 2 additions & 0 deletions src/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use memuse::DynamicUsage;
use nonempty::NonEmpty;
use zcash_note_encryption::{try_note_decryption, try_output_recovery_with_ovk};

use crate::note::NoteType;
use crate::{
action::Action,
address::Address,
Expand Down Expand Up @@ -376,6 +377,7 @@ impl<T: Authorization, V: Copy + Into<i64>> Bundle<T, V> {
- ValueCommitment::derive(
ValueSum::from_raw(self.value_balance.into()),
ValueCommitTrapdoor::zero(),
NoteType::native(),
))
.into_bvk()
}
Expand Down
3 changes: 2 additions & 1 deletion src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,7 @@ mod tests {
use rand::{rngs::OsRng, RngCore};

use super::{Circuit, Instance, Proof, ProvingKey, VerifyingKey, K};
use crate::note::NoteType;
use crate::{
keys::SpendValidatingKey,
note::Note,
Expand All @@ -905,7 +906,7 @@ mod tests {

let value = spent_note.value() - output_note.value();
let rcv = ValueCommitTrapdoor::random(&mut rng);
let cv_net = ValueCommitment::derive(value, rcv.clone());
let cv_net = ValueCommitment::derive(value, rcv, NoteType::native());

let path = MerklePath::dummy(&mut rng);
let anchor = path.root(spent_note.commitment().into());
Expand Down
4 changes: 4 additions & 0 deletions src/constants/fixed_bases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ pub mod value_commit_v;
pub const ORCHARD_PERSONALIZATION: &str = "z.cash:Orchard";

/// SWU hash-to-curve personalization for the value commitment generator
/// TODO: should we change to "NOTE_TYPE_PERSONALIZATION"?
pub const VALUE_COMMITMENT_PERSONALIZATION: &str = "z.cash:Orchard-cv";

/// SWU hash-to-curve personalization for the note type generator
// pub const NOTE_TYPE_PERSONALIZATION: &str = "z.cash:Orchard-NoteType";

/// SWU hash-to-curve value for the value commitment generator
pub const VALUE_COMMITMENT_V_BYTES: [u8; 1] = *b"v";

Expand Down
2 changes: 2 additions & 0 deletions src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,7 @@ mod tests {
testing::{arb_diversifier_index, arb_diversifier_key, arb_esk, arb_spending_key},
*,
};
use crate::note::NoteType;
use crate::{
note::{ExtractedNoteCommitment, Nullifier, RandomSeed},
value::NoteValue,
Expand Down Expand Up @@ -1136,6 +1137,7 @@ mod tests {
let note = Note::from_parts(
addr,
NoteValue::from_raw(tv.note_v),
NoteType::native(),
rho,
RandomSeed::from_bytes(tv.note_rseed, &rho).unwrap(),
);
Expand Down
18 changes: 18 additions & 0 deletions src/note.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ pub use self::commitment::{ExtractedNoteCommitment, NoteCommitment};
pub(crate) mod nullifier;
pub use self::nullifier::Nullifier;

pub(crate) mod note_type;
pub use self::note_type::NoteType;

/// The ZIP 212 seed randomness for a note.
#[derive(Copy, Clone, Debug)]
pub(crate) struct RandomSeed([u8; 32]);
Expand Down Expand Up @@ -86,6 +89,8 @@ pub struct Note {
recipient: Address,
/// The value of this note.
value: NoteValue,
/// The type of this note.
note_type: NoteType,
/// A unique creation ID for this note.
///
/// This is set to the nullifier of the note that was spent in the [`Action`] that
Expand All @@ -111,12 +116,14 @@ impl Note {
pub(crate) fn from_parts(
recipient: Address,
value: NoteValue,
note_type: NoteType,
rho: Nullifier,
rseed: RandomSeed,
) -> Self {
Note {
recipient,
value,
note_type,
rho,
rseed,
}
Expand All @@ -130,13 +137,15 @@ impl Note {
pub(crate) fn new(
recipient: Address,
value: NoteValue,
note_type: NoteType,
rho: Nullifier,
mut rng: impl RngCore,
) -> Self {
loop {
let note = Note {
recipient,
value,
note_type,
rho,
rseed: RandomSeed::random(&mut rng, &rho),
};
Expand All @@ -162,6 +171,7 @@ impl Note {
let note = Note::new(
recipient,
NoteValue::zero(),
NoteType::native(),
rho.unwrap_or_else(|| Nullifier::dummy(rng)),
rng,
);
Expand All @@ -179,6 +189,11 @@ impl Note {
self.value
}

/// Returns the note type
pub fn note_type(&self) -> NoteType {
self.note_type
}

/// Returns the rseed value of this note.
pub(crate) fn rseed(&self) -> &RandomSeed {
&self.rseed
Expand Down Expand Up @@ -265,6 +280,7 @@ impl fmt::Debug for TransmittedNoteCiphertext {
pub mod testing {
use proptest::prelude::*;

use crate::note::note_type::testing::arb_note_type;
use crate::{
address::testing::arb_address, note::nullifier::testing::arb_nullifier, value::NoteValue,
};
Expand All @@ -284,10 +300,12 @@ pub mod testing {
recipient in arb_address(),
rho in arb_nullifier(),
rseed in arb_rseed(),
note_type in arb_note_type(),
) -> Note {
Note {
recipient,
value,
note_type,
rho,
rseed,
}
Expand Down
77 changes: 77 additions & 0 deletions src/note/note_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use group::GroupEncoding;
use halo2_proofs::arithmetic::CurveExt;
use pasta_curves::pallas;
use subtle::CtOption;

use crate::constants::fixed_bases::{VALUE_COMMITMENT_PERSONALIZATION, VALUE_COMMITMENT_V_BYTES};
use crate::keys::IssuerValidatingKey;

/// Note type identifier.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct NoteType(pub(crate) pallas::Point);

const MAX_ASSET_DESCRIPTION_SIZE: usize = 512;

// the hasher used to derive the assetID
#[allow(non_snake_case)]
fn assetID_hasher(msg: Vec<u8>) -> pallas::Point {
// TODO(zsa) replace personalization, will require circuit change?
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--> no

pallas::Point::hash_to_curve(VALUE_COMMITMENT_PERSONALIZATION)(&msg)
}

impl NoteType {
/// Deserialize the note_type from a byte array.
pub fn from_bytes(bytes: &[u8; 32]) -> CtOption<Self> {
pallas::Point::from_bytes(bytes).map(NoteType)
}

/// Serialize the note_type to its canonical byte representation.
pub fn to_bytes(self) -> [u8; 32] {
self.0.to_bytes()
}

/// $DeriveNoteType$.
///
/// Defined in [Zcash Protocol Spec § TBD: Note Types][notetypes].
///
/// [notetypes]: https://zips.z.cash/protocol/nu5.pdf#notetypes
#[allow(non_snake_case)]
pub fn derive(ik: &IssuerValidatingKey, assetDesc: Vec<u8>) -> Self {
assert!(assetDesc.len() < MAX_ASSET_DESCRIPTION_SIZE);

let mut s = vec![];
s.extend(ik.to_bytes());
s.extend(assetDesc);

NoteType(assetID_hasher(s))
}

/// Note type for the "native" currency (zec), maintains backward compatibility with Orchard untyped notes.
pub fn native() -> Self {
NoteType(assetID_hasher(VALUE_COMMITMENT_V_BYTES.to_vec()))
}
}

/// Generators for property testing.
#[cfg(any(test, feature = "test-dependencies"))]
#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))]
pub mod testing {
use proptest::prelude::*;

use super::NoteType;

use crate::keys::{testing::arb_spending_key, IssuerAuthorizingKey, IssuerValidatingKey};

prop_compose! {
/// Generate a uniformly distributed note type
pub fn arb_note_type()(
sk in arb_spending_key(),
bytes32a in prop::array::uniform32(prop::num::u8::ANY),
bytes32b in prop::array::uniform32(prop::num::u8::ANY),
) -> NoteType {
let bytes64 = [bytes32a, bytes32b].concat();
let isk = IssuerAuthorizingKey::from(&sk);
NoteType::derive(&IssuerValidatingKey::from(&isk), bytes64)
}
}
}
8 changes: 6 additions & 2 deletions src/note_encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use zcash_note_encryption::{
OUT_PLAINTEXT_SIZE,
};

use crate::note::NoteType;
use crate::{
action::Action,
keys::{
Expand Down Expand Up @@ -75,7 +76,8 @@ where
let pk_d = get_validated_pk_d(&diversifier)?;

let recipient = Address::from_parts(diversifier, pk_d);
let note = Note::from_parts(recipient, value, domain.rho, rseed);
// TODO: add note_type
let note = Note::from_parts(recipient, value, NoteType::native(), domain.rho, rseed);
Some((note, recipient))
}

Expand Down Expand Up @@ -151,6 +153,7 @@ impl Domain for OrchardDomain {
np[0] = 0x02;
np[1..12].copy_from_slice(note.recipient().diversifier().as_array());
np[12..20].copy_from_slice(&note.value().to_bytes());
// todo: add note_type
np[20..52].copy_from_slice(note.rseed().as_bytes());
np[52..].copy_from_slice(memo);
NotePlaintextBytes(np)
Expand Down Expand Up @@ -316,6 +319,7 @@ mod tests {
};

use super::{prf_ock_orchard, CompactAction, OrchardDomain, OrchardNoteEncryption};
use crate::note::NoteType;
use crate::{
action::Action,
keys::{
Expand Down Expand Up @@ -369,7 +373,7 @@ mod tests {
assert_eq!(ock.as_ref(), tv.ock);

let recipient = Address::from_parts(d, pk_d);
let note = Note::from_parts(recipient, value, rho, rseed);
let note = Note::from_parts(recipient, value, NoteType::native(), rho, rseed);
assert_eq!(ExtractedNoteCommitment::from(note.commitment()), cmx);

let action = Action::from_parts(
Expand Down
Loading