Compare commits
17 Commits
Author | SHA1 | Date |
---|---|---|
str4d | 7db1c6fe5e | |
Jack Grigg | 461d99d42d | |
Jack Grigg | 9c76d5789f | |
Kris Nuttycombe | b459f710c2 | |
Kris Nuttycombe | 642ac4b7a7 | |
Kris Nuttycombe | f000a52148 | |
Kris Nuttycombe | 5076943e69 | |
Kris Nuttycombe | a7fa69c504 | |
Jack Grigg | 81d8f61b0d | |
Kris Nuttycombe | 9198dc7748 | |
Kris Nuttycombe | 8e2955da7c | |
Kris Nuttycombe | e66605f78f | |
Kris Nuttycombe | d8885bec55 | |
Kris Nuttycombe | f13c6cb13c | |
Kris Nuttycombe | 8d0d9c9510 | |
Kris Nuttycombe | b060f1c1df | |
str4d | cd883e2227 |
|
@ -0,0 +1,10 @@
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
timezone: Etc/UTC
|
||||||
|
open-pull-requests-limit: 10
|
||||||
|
labels:
|
||||||
|
- "A-CI"
|
|
@ -0,0 +1,88 @@
|
||||||
|
name: CI checks
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Test on ${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Run tests
|
||||||
|
run: cargo test --all-features --verbose
|
||||||
|
- name: Verify working directory is clean
|
||||||
|
run: git diff --exit-code
|
||||||
|
|
||||||
|
build-latest:
|
||||||
|
name: Latest build on ${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
id: toolchain
|
||||||
|
- run: rustup override set ${{steps.toolchain.outputs.name}}
|
||||||
|
- name: Remove lockfile to build with latest dependencies
|
||||||
|
run: rm Cargo.lock
|
||||||
|
- name: Build crate
|
||||||
|
run: cargo build --all-targets --all-features --verbose
|
||||||
|
- name: Verify working directory is clean (excluding lockfile)
|
||||||
|
run: git diff --exit-code ':!Cargo.lock'
|
||||||
|
|
||||||
|
build-nodefault:
|
||||||
|
name: Build target ${{ matrix.target }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
target:
|
||||||
|
- wasm32-wasi
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Add target
|
||||||
|
run: rustup target add ${{ matrix.target }}
|
||||||
|
- name: Build crate
|
||||||
|
run: cargo build --no-default-features --verbose --target ${{ matrix.target }}
|
||||||
|
|
||||||
|
bitrot:
|
||||||
|
name: Bitrot check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
# Build benchmarks to prevent bitrot
|
||||||
|
- name: Build benchmarks
|
||||||
|
run: cargo build --benches
|
||||||
|
|
||||||
|
clippy:
|
||||||
|
name: Clippy (MSRV)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Run Clippy
|
||||||
|
uses: auguwu/clippy-action@1.3.0
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
working-directory: ${{ inputs.target }}
|
||||||
|
deny: warnings
|
||||||
|
|
||||||
|
doc-links:
|
||||||
|
name: Intra-doc links
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- run: cargo fetch
|
||||||
|
# Requires #![deny(rustdoc::broken_intra_doc_links)] in crate.
|
||||||
|
- name: Check intra-doc links
|
||||||
|
run: cargo doc --all-features --document-private-items
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
name: Rustfmt
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Check formatting
|
||||||
|
run: cargo fmt -- --check
|
|
@ -0,0 +1 @@
|
||||||
|
target
|
19
CHANGELOG.md
19
CHANGELOG.md
|
@ -7,6 +7,25 @@ and this library adheres to Rust's notion of
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.4.0] - 2023-06-06
|
||||||
|
### Changed
|
||||||
|
- The `esk` and `ephemeral_key` arguments have been removed from
|
||||||
|
`Domain::parse_note_plaintext_without_memo_ovk`. It is therefore no longer
|
||||||
|
necessary (or possible) to ensure that `ephemeral_key` is derived from `esk`
|
||||||
|
and the diversifier within the note plaintext. We have analyzed the safety of
|
||||||
|
this change in the context of callers within `zcash_note_encryption` and
|
||||||
|
`orchard`. See https://github.com/zcash/librustzcash/pull/848 and the
|
||||||
|
associated issue https://github.com/zcash/librustzcash/issues/802 for
|
||||||
|
additional detail.
|
||||||
|
|
||||||
|
## [0.3.0] - 2023-03-22
|
||||||
|
### Changed
|
||||||
|
- The `recipient` parameter has been removed from `Domain::note_plaintext_bytes`.
|
||||||
|
- The `recipient` parameter has been removed from `NoteEncryption::new`. Since
|
||||||
|
the `Domain::Note` type is now expected to contain information about the
|
||||||
|
recipient of the note, there is no longer any need to pass this information
|
||||||
|
in via the encryption context.
|
||||||
|
|
||||||
## [0.2.0] - 2022-10-13
|
## [0.2.0] - 2022-10-13
|
||||||
### Added
|
### Added
|
||||||
- `zcash_note_encryption::Domain`:
|
- `zcash_note_encryption::Domain`:
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aead"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chacha20"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cipher",
|
||||||
|
"cpufeatures",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chacha20poly1305"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
|
||||||
|
dependencies = [
|
||||||
|
"aead",
|
||||||
|
"chacha20",
|
||||||
|
"cipher",
|
||||||
|
"poly1305",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cipher"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"inout",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inout"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.150"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opaque-debug"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "poly1305"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
|
||||||
|
dependencies = [
|
||||||
|
"cpufeatures",
|
||||||
|
"opaque-debug",
|
||||||
|
"universal-hash",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "universal-hash"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zcash_note_encryption"
|
||||||
|
version = "0.4.0"
|
||||||
|
dependencies = [
|
||||||
|
"chacha20",
|
||||||
|
"chacha20poly1305",
|
||||||
|
"cipher",
|
||||||
|
"rand_core",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "zcash_note_encryption"
|
name = "zcash_note_encryption"
|
||||||
description = "Note encryption for Zcash transactions"
|
description = "Note encryption for Zcash transactions"
|
||||||
version = "0.2.0"
|
version = "0.4.0"
|
||||||
authors = [
|
authors = [
|
||||||
"Jack Grigg <jack@electriccoin.co>",
|
"Jack Grigg <jack@electriccoin.co>",
|
||||||
"Kris Nuttycombe <kris@electriccoin.co>"
|
"Kris Nuttycombe <kris@electriccoin.co>"
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[toolchain]
|
||||||
|
channel = "1.56.1"
|
||||||
|
components = ["clippy", "rustfmt"]
|
65
src/lib.rs
65
src/lib.rs
|
@ -19,6 +19,8 @@
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
// TODO: #![deny(missing_docs)]
|
// TODO: #![deny(missing_docs)]
|
||||||
|
|
||||||
|
use core::fmt::{self, Write};
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
@ -72,9 +74,28 @@ impl AsRef<[u8]> for OutgoingCipherKey {
|
||||||
/// Newtype representing the byte encoding of an [`EphemeralPublicKey`].
|
/// Newtype representing the byte encoding of an [`EphemeralPublicKey`].
|
||||||
///
|
///
|
||||||
/// [`EphemeralPublicKey`]: Domain::EphemeralPublicKey
|
/// [`EphemeralPublicKey`]: Domain::EphemeralPublicKey
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
pub struct EphemeralKeyBytes(pub [u8; 32]);
|
pub struct EphemeralKeyBytes(pub [u8; 32]);
|
||||||
|
|
||||||
|
impl fmt::Debug for EphemeralKeyBytes {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
struct HexFmt<'b>(&'b [u8]);
|
||||||
|
impl<'b> fmt::Debug for HexFmt<'b> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_char('"')?;
|
||||||
|
for b in self.0 {
|
||||||
|
f.write_fmt(format_args!("{:02x}", b))?;
|
||||||
|
}
|
||||||
|
f.write_char('"')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.debug_tuple("EphemeralKeyBytes")
|
||||||
|
.field(&HexFmt(&self.0))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AsRef<[u8]> for EphemeralKeyBytes {
|
impl AsRef<[u8]> for EphemeralKeyBytes {
|
||||||
fn as_ref(&self) -> &[u8] {
|
fn as_ref(&self) -> &[u8] {
|
||||||
&self.0
|
&self.0
|
||||||
|
@ -171,20 +192,7 @@ pub trait Domain {
|
||||||
fn kdf(secret: Self::SharedSecret, ephemeral_key: &EphemeralKeyBytes) -> Self::SymmetricKey;
|
fn kdf(secret: Self::SharedSecret, ephemeral_key: &EphemeralKeyBytes) -> Self::SymmetricKey;
|
||||||
|
|
||||||
/// Encodes the given `Note` and `Memo` as a note plaintext.
|
/// Encodes the given `Note` and `Memo` as a note plaintext.
|
||||||
///
|
fn note_plaintext_bytes(note: &Self::Note, memo: &Self::Memo) -> NotePlaintextBytes;
|
||||||
/// # Future breaking changes
|
|
||||||
///
|
|
||||||
/// The `recipient` argument is present as a secondary way to obtain the diversifier;
|
|
||||||
/// this is due to a historical quirk of how the Sapling `Note` struct was implemented
|
|
||||||
/// in the `zcash_primitives` crate. `recipient` will be removed from this method in a
|
|
||||||
/// future crate release, once [`zcash_primitives` has been refactored].
|
|
||||||
///
|
|
||||||
/// [`zcash_primitives` has been refactored]: https://github.com/zcash/librustzcash/issues/454
|
|
||||||
fn note_plaintext_bytes(
|
|
||||||
note: &Self::Note,
|
|
||||||
recipient: &Self::Recipient,
|
|
||||||
memo: &Self::Memo,
|
|
||||||
) -> NotePlaintextBytes;
|
|
||||||
|
|
||||||
/// Derives the [`OutgoingCipherKey`] for an encrypted note, given the note-specific
|
/// Derives the [`OutgoingCipherKey`] for an encrypted note, given the note-specific
|
||||||
/// public data and an `OutgoingViewingKey`.
|
/// public data and an `OutgoingViewingKey`.
|
||||||
|
@ -242,8 +250,6 @@ pub trait Domain {
|
||||||
/// which may be passed via `self`).
|
/// which may be passed via `self`).
|
||||||
/// - The note plaintext contains valid encodings of its various fields.
|
/// - The note plaintext contains valid encodings of its various fields.
|
||||||
/// - Any domain-specific requirements are satisfied.
|
/// - Any domain-specific requirements are satisfied.
|
||||||
/// - `ephemeral_key` can be derived from `esk` and the diversifier within the note
|
|
||||||
/// plaintext.
|
|
||||||
///
|
///
|
||||||
/// `&self` is passed here to enable the implementation to enforce contextual checks,
|
/// `&self` is passed here to enable the implementation to enforce contextual checks,
|
||||||
/// such as rules like [ZIP 212] that become active at a specific block height.
|
/// such as rules like [ZIP 212] that become active at a specific block height.
|
||||||
|
@ -252,8 +258,6 @@ pub trait Domain {
|
||||||
fn parse_note_plaintext_without_memo_ovk(
|
fn parse_note_plaintext_without_memo_ovk(
|
||||||
&self,
|
&self,
|
||||||
pk_d: &Self::DiversifiedTransmissionKey,
|
pk_d: &Self::DiversifiedTransmissionKey,
|
||||||
esk: &Self::EphemeralSecretKey,
|
|
||||||
ephemeral_key: &EphemeralKeyBytes,
|
|
||||||
plaintext: &NotePlaintextBytes,
|
plaintext: &NotePlaintextBytes,
|
||||||
) -> Option<(Self::Note, Self::Recipient)>;
|
) -> Option<(Self::Note, Self::Recipient)>;
|
||||||
|
|
||||||
|
@ -349,7 +353,6 @@ pub struct NoteEncryption<D: Domain> {
|
||||||
epk: D::EphemeralPublicKey,
|
epk: D::EphemeralPublicKey,
|
||||||
esk: D::EphemeralSecretKey,
|
esk: D::EphemeralSecretKey,
|
||||||
note: D::Note,
|
note: D::Note,
|
||||||
to: D::Recipient,
|
|
||||||
memo: D::Memo,
|
memo: D::Memo,
|
||||||
/// `None` represents the `ovk = ⊥` case.
|
/// `None` represents the `ovk = ⊥` case.
|
||||||
ovk: Option<D::OutgoingViewingKey>,
|
ovk: Option<D::OutgoingViewingKey>,
|
||||||
|
@ -358,18 +361,12 @@ pub struct NoteEncryption<D: Domain> {
|
||||||
impl<D: Domain> NoteEncryption<D> {
|
impl<D: Domain> NoteEncryption<D> {
|
||||||
/// Construct a new note encryption context for the specified note,
|
/// Construct a new note encryption context for the specified note,
|
||||||
/// recipient, and memo.
|
/// recipient, and memo.
|
||||||
pub fn new(
|
pub fn new(ovk: Option<D::OutgoingViewingKey>, note: D::Note, memo: D::Memo) -> Self {
|
||||||
ovk: Option<D::OutgoingViewingKey>,
|
|
||||||
note: D::Note,
|
|
||||||
to: D::Recipient,
|
|
||||||
memo: D::Memo,
|
|
||||||
) -> Self {
|
|
||||||
let esk = D::derive_esk(¬e).expect("ZIP 212 is active.");
|
let esk = D::derive_esk(¬e).expect("ZIP 212 is active.");
|
||||||
NoteEncryption {
|
NoteEncryption {
|
||||||
epk: D::ka_derive_public(¬e, &esk),
|
epk: D::ka_derive_public(¬e, &esk),
|
||||||
esk,
|
esk,
|
||||||
note,
|
note,
|
||||||
to,
|
|
||||||
memo,
|
memo,
|
||||||
ovk,
|
ovk,
|
||||||
}
|
}
|
||||||
|
@ -384,14 +381,12 @@ impl<D: Domain> NoteEncryption<D> {
|
||||||
esk: D::EphemeralSecretKey,
|
esk: D::EphemeralSecretKey,
|
||||||
ovk: Option<D::OutgoingViewingKey>,
|
ovk: Option<D::OutgoingViewingKey>,
|
||||||
note: D::Note,
|
note: D::Note,
|
||||||
to: D::Recipient,
|
|
||||||
memo: D::Memo,
|
memo: D::Memo,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
NoteEncryption {
|
NoteEncryption {
|
||||||
epk: D::ka_derive_public(¬e, &esk),
|
epk: D::ka_derive_public(¬e, &esk),
|
||||||
esk,
|
esk,
|
||||||
note,
|
note,
|
||||||
to,
|
|
||||||
memo,
|
memo,
|
||||||
ovk,
|
ovk,
|
||||||
}
|
}
|
||||||
|
@ -412,7 +407,7 @@ impl<D: Domain> NoteEncryption<D> {
|
||||||
let pk_d = D::get_pk_d(&self.note);
|
let pk_d = D::get_pk_d(&self.note);
|
||||||
let shared_secret = D::ka_agree_enc(&self.esk, &pk_d);
|
let shared_secret = D::ka_agree_enc(&self.esk, &pk_d);
|
||||||
let key = D::kdf(shared_secret, &D::epk_bytes(&self.epk));
|
let key = D::kdf(shared_secret, &D::epk_bytes(&self.epk));
|
||||||
let input = D::note_plaintext_bytes(&self.note, &self.to, &self.memo);
|
let input = D::note_plaintext_bytes(&self.note, &self.memo);
|
||||||
|
|
||||||
let mut output = [0u8; ENC_CIPHERTEXT_SIZE];
|
let mut output = [0u8; ENC_CIPHERTEXT_SIZE];
|
||||||
output[..NOTE_PLAINTEXT_SIZE].copy_from_slice(&input.0);
|
output[..NOTE_PLAINTEXT_SIZE].copy_from_slice(&input.0);
|
||||||
|
@ -539,6 +534,8 @@ fn check_note_validity<D: Domain>(
|
||||||
cmstar_bytes: &D::ExtractedCommitmentBytes,
|
cmstar_bytes: &D::ExtractedCommitmentBytes,
|
||||||
) -> NoteValidity {
|
) -> NoteValidity {
|
||||||
if &D::ExtractedCommitmentBytes::from(&D::cmstar(note)) == cmstar_bytes {
|
if &D::ExtractedCommitmentBytes::from(&D::cmstar(note)) == cmstar_bytes {
|
||||||
|
// In the case corresponding to specification section 4.19.3, we check that `esk` is equal
|
||||||
|
// to `D::derive_esk(note)` prior to calling this method.
|
||||||
if let Some(derived_esk) = D::derive_esk(note) {
|
if let Some(derived_esk) = D::derive_esk(note) {
|
||||||
if D::epk_bytes(&D::ka_derive_public(note, &derived_esk))
|
if D::epk_bytes(&D::ka_derive_public(note, &derived_esk))
|
||||||
.ct_eq(ephemeral_key)
|
.ct_eq(ephemeral_key)
|
||||||
|
@ -677,12 +674,12 @@ pub fn try_output_recovery_with_ock<D: Domain, Output: ShieldedOutput<D, ENC_CIP
|
||||||
)
|
)
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
let (note, to) =
|
let (note, to) = domain.parse_note_plaintext_without_memo_ovk(&pk_d, &plaintext)?;
|
||||||
domain.parse_note_plaintext_without_memo_ovk(&pk_d, &esk, &ephemeral_key, &plaintext)?;
|
|
||||||
let memo = domain.extract_memo(&plaintext);
|
let memo = domain.extract_memo(&plaintext);
|
||||||
|
|
||||||
// ZIP 212: Check that the esk provided to this function is consistent with the esk we
|
// ZIP 212: Check that the esk provided to this function is consistent with the esk we can
|
||||||
// can derive from the note.
|
// derive from the note. This check corresponds to `ToScalar(PRF^{expand}_{rseed}([4]) = esk`
|
||||||
|
// in https://zips.z.cash/protocol/protocol.pdf#decryptovk. (`ρ^opt = []` for Sapling.)
|
||||||
if let Some(derived_esk) = D::derive_esk(¬e) {
|
if let Some(derived_esk) = D::derive_esk(¬e) {
|
||||||
if (!derived_esk.ct_eq(&esk)).into() {
|
if (!derived_esk.ct_eq(&esk)).into() {
|
||||||
return None;
|
return None;
|
||||||
|
|
Loading…
Reference in New Issue