diff --git a/Cargo.lock b/Cargo.lock index e63687beb..5cabd2c1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aes" version = "0.6.0" @@ -93,6 +95,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "base64ct" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" + [[package]] name = "bech32" version = "0.8.1" @@ -138,6 +146,20 @@ dependencies = [ "serde", ] +[[package]] +name = "bip0039" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac4d1925000f9183da41ed95477ea815512b5bb7e06e6c6964986ca077e2b75c" +dependencies = [ + "hmac", + "pbkdf2", + "rand", + "sha2", + "unicode-normalization", + "zeroize", +] + [[package]] name = "bitflags" version = "1.2.1" @@ -294,7 +316,7 @@ checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" dependencies = [ "cfg-if 0.1.10", "crossbeam-channel 0.4.4", - "crossbeam-deque", + "crossbeam-deque 0.7.3", "crossbeam-epoch 0.8.2", "crossbeam-queue", "crossbeam-utils 0.7.2", @@ -331,6 +353,17 @@ dependencies = [ "maybe-uninit", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch 0.9.5", + "crossbeam-utils 0.8.5", +] + [[package]] name = "crossbeam-epoch" version = "0.8.2" @@ -397,6 +430,16 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "crypto_api" version = "0.2.2" @@ -488,6 +531,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + [[package]] name = "endian-type" version = "0.1.2" @@ -497,7 +546,7 @@ checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" [[package]] name = "equihash" version = "0.1.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=1a40fc9ac82bf43da15cb36d3757fdf610be1bd2#1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" +source = "git+https://github.com/zcash/librustzcash.git?rev=98dc330cdb1c96e980e62b5bc901edbaa128fea2#98dc330cdb1c96e980e62b5bc901edbaa128fea2" dependencies = [ "blake2b_simd", "byteorder", @@ -636,15 +685,14 @@ dependencies = [ [[package]] name = "halo2" version = "0.0.1" -source = "git+https://github.com/zcash/halo2.git?rev=d04b532368d05b505e622f8cac4c0693574fbd93#d04b532368d05b505e622f8cac4c0693574fbd93" +source = "git+https://github.com/zcash/halo2.git?rev=27c4187673a9c6ade13fbdbd4f20955530c22d7f#27c4187673a9c6ade13fbdbd4f20955530c22d7f" dependencies = [ "blake2b_simd", - "crossbeam-utils 0.8.5", "ff", "group", - "num_cpus", "pasta_curves", "rand", + "rayon", ] [[package]] @@ -671,6 +719,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest", +] + [[package]] name = "http" version = "0.2.4" @@ -770,8 +828,7 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "jubjub" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "593fc4726ca80edb47ee18ab4d826719e25c2096991a79308b44fb915c6014ef" +source = "git+https://github.com/zkcrypto/jubjub.git?rev=96ab4162b83303378eae32a326b54d88b75bffc2#96ab4162b83303378eae32a326b54d88b75bffc2" dependencies = [ "bitvec", "bls12_381", @@ -1060,10 +1117,11 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "orchard" version = "0.0.0" -source = "git+https://github.com/zcash/orchard.git?rev=74df35ce890726478983fb892ff38a5e44ceb08a#74df35ce890726478983fb892ff38a5e44ceb08a" +source = "git+https://github.com/zcash/orchard.git?rev=8454f86d423edbf0b53a1d5d32df1c691f8b7188#8454f86d423edbf0b53a1d5d32df1c691f8b7188" dependencies = [ "aes", "arrayvec 0.7.1", + "bigint", "bitvec", "blake2b_simd", "ff", @@ -1124,6 +1182,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "password-hash" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd482dfb8cfba5a93ec0f91e1c0f66967cb2fdc1a8dba646c4f9202c5d05d785" +dependencies = [ + "base64ct", + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "pasta_curves" version = "0.1.1" @@ -1139,6 +1208,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "pbkdf2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" +dependencies = [ + "crypto-mac", + "password-hash", +] + [[package]] name = "pin-project" version = "1.0.8" @@ -1290,6 +1369,31 @@ dependencies = [ "bitflags", ] +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque 0.8.1", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel 0.5.1", + "crossbeam-deque 0.8.1", + "crossbeam-utils 0.8.5", + "lazy_static", + "num_cpus", +] + [[package]] name = "reddsa" version = "0.0.0" @@ -1503,6 +1607,21 @@ dependencies = [ "winapi", ] +[[package]] +name = "tinyvec" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + [[package]] name = "tokio" version = "1.9.0" @@ -1606,6 +1725,15 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-xid" version = "0.2.2" @@ -1674,7 +1802,7 @@ dependencies = [ [[package]] name = "zcash_address" version = "0.0.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=1a40fc9ac82bf43da15cb36d3757fdf610be1bd2#1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" +source = "git+https://github.com/zcash/librustzcash.git?rev=98dc330cdb1c96e980e62b5bc901edbaa128fea2#98dc330cdb1c96e980e62b5bc901edbaa128fea2" dependencies = [ "bech32", "blake2b_simd", @@ -1684,7 +1812,7 @@ dependencies = [ [[package]] name = "zcash_history" version = "0.2.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=1a40fc9ac82bf43da15cb36d3757fdf610be1bd2#1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" +source = "git+https://github.com/zcash/librustzcash.git?rev=98dc330cdb1c96e980e62b5bc901edbaa128fea2#98dc330cdb1c96e980e62b5bc901edbaa128fea2" dependencies = [ "bigint", "blake2b_simd", @@ -1694,7 +1822,7 @@ dependencies = [ [[package]] name = "zcash_note_encryption" version = "0.0.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=1a40fc9ac82bf43da15cb36d3757fdf610be1bd2#1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" +source = "git+https://github.com/zcash/librustzcash.git?rev=98dc330cdb1c96e980e62b5bc901edbaa128fea2#98dc330cdb1c96e980e62b5bc901edbaa128fea2" dependencies = [ "blake2b_simd", "byteorder", @@ -1708,9 +1836,10 @@ dependencies = [ [[package]] name = "zcash_primitives" version = "0.5.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=1a40fc9ac82bf43da15cb36d3757fdf610be1bd2#1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" +source = "git+https://github.com/zcash/librustzcash.git?rev=98dc330cdb1c96e980e62b5bc901edbaa128fea2#98dc330cdb1c96e980e62b5bc901edbaa128fea2" dependencies = [ "aes", + "bip0039", "bitvec", "blake2b_simd", "blake2s_simd", @@ -1738,7 +1867,7 @@ dependencies = [ [[package]] name = "zcash_proofs" version = "0.5.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=1a40fc9ac82bf43da15cb36d3757fdf610be1bd2#1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" +source = "git+https://github.com/zcash/librustzcash.git?rev=98dc330cdb1c96e980e62b5bc901edbaa128fea2#98dc330cdb1c96e980e62b5bc901edbaa128fea2" dependencies = [ "bellman", "blake2b_simd", diff --git a/Cargo.toml b/Cargo.toml index b31dcdf5b..80f8f7ebc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,11 +64,12 @@ codegen-units = 1 [patch.crates-io] ed25519-zebra = { git = "https://github.com/ZcashFoundation/ed25519-zebra.git", rev = "d3512400227a362d08367088ffaa9bd4142a69c7" } -halo2 = { git = "https://github.com/zcash/halo2.git", rev = "d04b532368d05b505e622f8cac4c0693574fbd93" } +halo2 = { git = "https://github.com/zcash/halo2.git", rev = "27c4187673a9c6ade13fbdbd4f20955530c22d7f" } incrementalmerkletree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "8b59049f1746827ffa3763efa8af948f680491d0" } -orchard = { git = "https://github.com/zcash/orchard.git", rev = "74df35ce890726478983fb892ff38a5e44ceb08a" } -zcash_address = { git = "https://github.com/zcash/librustzcash.git", rev = "1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" } -zcash_history = { git = "https://github.com/zcash/librustzcash.git", rev = "1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" } -zcash_note_encryption = { git = "https://github.com/zcash/librustzcash.git", rev = "1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" } -zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" } -zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "1a40fc9ac82bf43da15cb36d3757fdf610be1bd2" } +jubjub = { git = "https://github.com/zkcrypto/jubjub.git", rev = "96ab4162b83303378eae32a326b54d88b75bffc2" } +orchard = { git = "https://github.com/zcash/orchard.git", rev = "8454f86d423edbf0b53a1d5d32df1c691f8b7188" } +zcash_address = { git = "https://github.com/zcash/librustzcash.git", rev = "98dc330cdb1c96e980e62b5bc901edbaa128fea2" } +zcash_history = { git = "https://github.com/zcash/librustzcash.git", rev = "98dc330cdb1c96e980e62b5bc901edbaa128fea2" } +zcash_note_encryption = { git = "https://github.com/zcash/librustzcash.git", rev = "98dc330cdb1c96e980e62b5bc901edbaa128fea2" } +zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "98dc330cdb1c96e980e62b5bc901edbaa128fea2" } +zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "98dc330cdb1c96e980e62b5bc901edbaa128fea2" } diff --git a/src/rust/include/rust/zip339.h b/src/rust/include/rust/zip339.h new file mode 100644 index 000000000..fa5b0d378 --- /dev/null +++ b/src/rust/include/rust/zip339.h @@ -0,0 +1,59 @@ +#ifndef ZCASH_RUST_INCLUDE_RUST_ZIP339_H +#define ZCASH_RUST_INCLUDE_RUST_ZIP339_H + +#include "rust/types.h" + +#include +#include + +#ifndef __cplusplus + #include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + // These must match src/rust/src/zip339_ffi.rs. + // (They happen to also match the integer values correspond in the bip0039-rs crate with the + // "all-languages" feature enabled, but that's not required.) + enum Language +#ifdef __cplusplus + : uint32_t +#endif + { + English = 0, + SimplifiedChinese = 1, + TraditionalChinese = 2, + Czech = 3, + French = 4, + Italian = 5, + Japanese = 6, + Korean = 7, + Portuguese = 8, + Spanish = 9, + SIZE_HACK = 0xFFFFFFFF // needed when compiling as C + }; + + static_assert(sizeof(Language) == 4); + + /// Creates a phrase with the given entropy, in the given `Language`. The phrase is represented as + /// a pointer to a null-terminated C string that must not be written to, and must be freed by + /// `zip339_free_phrase`. + const char * zip339_entropy_to_phrase(Language language, const uint8_t *entropy, size_t entropy_len); + + /// Frees a phrase returned by `zip339_entropy_to_phrase`. + void zip339_free_phrase(const char *phrase); + + /// Returns `true` if the given string is a valid mnemonic phrase in the given `Language`. + bool zip339_validate_phrase(Language language, const char *phrase); + + /// Copies the seed for the given phrase into the 64-byte buffer `buf`. + /// Returns true if successful, false on error. In case of error, `buf` is zeroed. + bool zip339_phrase_to_seed(Language language, const char *phrase, uint8_t (*buf)[64]); + +#ifdef __cplusplus +} +#endif + +#endif // ZCASH_RUST_INCLUDE_RUST_ZIP339_H diff --git a/src/rust/src/rustzcash.rs b/src/rust/src/rustzcash.rs index 09ba1bd87..cc5e1f232 100644 --- a/src/rust/src/rustzcash.rs +++ b/src/rust/src/rustzcash.rs @@ -72,6 +72,7 @@ mod address_ffi; mod history_ffi; mod orchard_ffi; mod transaction_ffi; +mod zip339_ffi; mod test_harness_ffi; diff --git a/src/rust/src/tests/mod.rs b/src/rust/src/tests/mod.rs index 2d1e35041..cea15547b 100644 --- a/src/rust/src/tests/mod.rs +++ b/src/rust/src/tests/mod.rs @@ -10,6 +10,7 @@ mod key_components; mod mmr; mod notes; mod signatures; +mod zip339; #[test] fn sapling_generators() { diff --git a/src/rust/src/tests/zip339.rs b/src/rust/src/tests/zip339.rs new file mode 100644 index 000000000..8ee72ec00 --- /dev/null +++ b/src/rust/src/tests/zip339.rs @@ -0,0 +1,120 @@ +use libc::c_char; +use std::{ + convert::{TryFrom, TryInto}, + ffi::CStr, + ptr, +}; + +use crate::zip339_ffi::{ + zip339_entropy_to_phrase, zip339_free_phrase, zip339_phrase_to_seed, zip339_validate_phrase, + Language, +}; +use zcash_primitives::zip339; + +#[test] +fn test_try_from_language() { + assert_eq!(Language(0).try_into(), Ok(zip339::Language::English)); + assert!(zip339::Language::try_from(Language(1234)).is_err()); +} + +#[test] +#[should_panic] +fn test_null_entropy_to_phrase_panics() { + zip339_entropy_to_phrase(Language(0), ptr::null(), 0); +} + +#[test] +fn test_free_null_phrase_is_noop() { + zip339_free_phrase(ptr::null_mut()); +} + +#[test] +#[should_panic] +fn test_validate_null_phrase_panics() { + zip339_validate_phrase(Language(0), ptr::null()); +} + +#[test] +#[should_panic] +fn test_null_phrase_to_seed_panics() { + zip339_phrase_to_seed(Language(0), ptr::null(), ptr::NonNull::dangling().as_ptr()); +} + +#[test] +#[should_panic] +fn test_phrase_to_seed_with_null_buffer_panics() { + zip339_phrase_to_seed( + Language(0), + ptr::NonNull::dangling().as_ptr(), + ptr::null_mut(), + ); +} + +#[test] +fn test_known_answers() { + let mut entropy = [0u8; 32]; + + // English and another language with non-Latin script. + let expected_phrase_en = "abandon abandon abandon abandon abandon abandon abandon abandon \ + abandon abandon abandon abandon abandon abandon abandon abandon \ + abandon abandon abandon abandon abandon abandon abandon art"; + let expected_phrase_ko = "가격 가격 가격 가격 가격 가격 가격 가격 \ + 가격 가격 가격 가격 가격 가격 가격 가격 \ + 가격 가격 가격 가격 가격 가격 가격 계단"; + + let expected_seed_en = [ + 0x40, 0x8B, 0x28, 0x5C, 0x12, 0x38, 0x36, 0x00, 0x4F, 0x4B, 0x88, 0x42, 0xC8, 0x93, 0x24, + 0xC1, 0xF0, 0x13, 0x82, 0x45, 0x0C, 0x0D, 0x43, 0x9A, 0xF3, 0x45, 0xBA, 0x7F, 0xC4, 0x9A, + 0xCF, 0x70, 0x54, 0x89, 0xC6, 0xFC, 0x77, 0xDB, 0xD4, 0xE3, 0xDC, 0x1D, 0xD8, 0xCC, 0x6B, + 0xC9, 0xF0, 0x43, 0xDB, 0x8A, 0xDA, 0x1E, 0x24, 0x3C, 0x4A, 0x0E, 0xAF, 0xB2, 0x90, 0xD3, + 0x99, 0x48, 0x08, 0x40, + ]; + let expected_seed_ko = [ + 0xD6, 0x93, 0x5F, 0x34, 0x3A, 0xC6, 0x66, 0x97, 0x58, 0x06, 0xDF, 0xA7, 0xBD, 0x0E, 0x45, + 0xF8, 0x3A, 0x6F, 0x0A, 0x1A, 0x9F, 0x48, 0x54, 0xF4, 0x40, 0xEC, 0x09, 0x0B, 0xE3, 0xEF, + 0x16, 0xEA, 0x09, 0x42, 0x03, 0xEC, 0x07, 0xA1, 0x7D, 0x8B, 0x43, 0x9B, 0xBD, 0x2F, 0x89, + 0x3D, 0xB8, 0xB8, 0x3D, 0x3E, 0x43, 0xD4, 0x59, 0xA3, 0x6C, 0x29, 0xDF, 0xAB, 0xC2, 0xF9, + 0xF5, 0xB2, 0x47, 0x72, + ]; + + for &(expected_phrase, expected_seed, language) in [ + (expected_phrase_en, expected_seed_en, Language(0)), + (expected_phrase_ko, expected_seed_ko, Language(7)), + ] + .iter() + { + // Testing these all together simplifies memory management in the test code. + + // test zip339_entropy_to_phrase + let phrase = zip339_entropy_to_phrase(language, entropy[..].as_mut_ptr(), 32); + assert_eq!( + unsafe { CStr::from_ptr(phrase) }.to_str().unwrap(), + expected_phrase + ); + + // test zip339_validate_phrase + assert!(zip339_validate_phrase(language, phrase)); + assert!(!zip339_validate_phrase(Language(1), phrase)); + assert!(!zip339_validate_phrase(Language(1234), phrase)); + + // test zip339_phrase_to_seed + let mut seed = [0u8; 64]; + assert!(zip339_phrase_to_seed( + language, + phrase, + seed[..].as_mut_ptr() + )); + assert_eq!(seed, expected_seed); + + // test that zip339_phrase_to_seed zeros buffer on failure + let mut seed = [0xFFu8; 64]; + assert!(!zip339_phrase_to_seed( + Language(1), + phrase, + seed[..].as_mut_ptr() + )); + assert_eq!(seed, [0u8; 64]); + + zip339_free_phrase(phrase as *mut c_char); + } +} diff --git a/src/rust/src/zip339_ffi.rs b/src/rust/src/zip339_ffi.rs new file mode 100644 index 000000000..eeafa5bcd --- /dev/null +++ b/src/rust/src/zip339_ffi.rs @@ -0,0 +1,111 @@ +use libc::{c_char, size_t}; +use std::{ + convert::{TryFrom, TryInto}, + ffi::{CStr, CString}, + ptr, slice, +}; + +use zcash_primitives::zip339; + +// It's safer to use a wrapper type here than an enum. We can't stop a C caller from passing +// an unrecognized value as a `language` parameter; if it were an enum on the Rust side, +// then that would immediately be UB, whereas this way we can return null or false. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Language(pub u32); + +impl TryFrom for zip339::Language { + type Error = (); + + fn try_from(language: Language) -> Result { + // These must match `src/rust/include/zip339.h`. + match language { + Language(0) => Ok(zip339::Language::English), + Language(1) => Ok(zip339::Language::SimplifiedChinese), + Language(2) => Ok(zip339::Language::TraditionalChinese), + Language(3) => Ok(zip339::Language::Czech), + Language(4) => Ok(zip339::Language::French), + Language(5) => Ok(zip339::Language::Italian), + Language(6) => Ok(zip339::Language::Japanese), + Language(7) => Ok(zip339::Language::Korean), + Language(8) => Ok(zip339::Language::Portuguese), + Language(9) => Ok(zip339::Language::Spanish), + Language(_) => Err(()), + } + } +} + +/// Creates a phrase with the given entropy, in the given `Language`. The phrase is represented as +/// a pointer to a null-terminated C string that must not be written to, and must be freed by +/// `zip339_free_phrase`. +#[no_mangle] +pub extern "C" fn zip339_entropy_to_phrase( + language: Language, + entropy: *const u8, + entropy_len: size_t, +) -> *const c_char { + assert!(!entropy.is_null()); + + if let Ok(language) = language.try_into() { + let entropy = unsafe { slice::from_raw_parts(entropy, entropy_len) }.to_vec(); + if let Ok(mnemonic) = zip339::Mnemonic::from_entropy_in(language, entropy) { + if let Ok(phrase) = CString::new(mnemonic.phrase()) { + return phrase.into_raw() as *const c_char; + } + } + } + ptr::null() +} + +/// Frees a phrase returned by `zip339_entropy_to_phrase`. +#[no_mangle] +pub extern "C" fn zip339_free_phrase(phrase: *const c_char) { + if !phrase.is_null() { + unsafe { + // It is correct to cast away const here; the memory is not actually immutable. + CString::from_raw(phrase as *mut c_char); + } + } +} + +/// Returns `true` if the given string is a valid mnemonic phrase in the given `Language`. +#[no_mangle] +pub extern "C" fn zip339_validate_phrase(language: Language, phrase: *const c_char) -> bool { + assert!(!phrase.is_null()); + + if let Ok(language) = language.try_into() { + if let Ok(phrase) = unsafe { CStr::from_ptr(phrase) }.to_str() { + return zip339::Mnemonic::validate_in(language, phrase).is_ok(); + } + } + false +} + +/// Copies the seed for the given phrase into the 64-byte buffer `buf`. +/// Returns true if successful, false on error. In case of error, `buf` is zeroed. +#[no_mangle] +pub extern "C" fn zip339_phrase_to_seed( + language: Language, + phrase: *const c_char, + buf: *mut u8, +) -> bool { + assert!(!phrase.is_null()); + assert!(!buf.is_null()); + + if let Ok(language) = language.try_into() { + if let Ok(phrase) = unsafe { CStr::from_ptr(phrase) }.to_str() { + if let Ok(mnemonic) = zip339::Mnemonic::from_phrase_in(language, phrase) { + // Use the empty passphrase. + let seed = mnemonic.to_seed(""); + unsafe { + ptr::copy(seed.as_ptr(), buf, 64); + } + return true; + } + } + } + unsafe { + ptr::write_bytes(buf, 0, 64); + } + false +} diff --git a/src/test/data/unified_addrs.json b/src/test/data/unified_addrs.json index 51ee6f806..dd14807df 100644 --- a/src/test/data/unified_addrs.json +++ b/src/test/data/unified_addrs.json @@ -1,14 +1,15 @@ [ ["From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/unified_address.py"], ["p2pkh_bytes, p2sh_bytes, sapling_raw_addr, orchard_raw_addr, unified_addr"], - [null, "7a8f739a2d9e945b0ce152a8049e294c4d6e66b1", null, "dcb1d2a37762148db4cee3bbf19fb1ec05891894b13801c622ba6a90faf1119f8224ae3985c6abd3b7bbae", "753178356b66326a646c37396b7170653964757a7a3979667a796a726437327364613671657032393265367a336c6c61767270796a6d7674363436306e6733667163773672636479656e6468756a6834643263767979357432687878347364787973326d76346767637a64327a676e73616166707835706173673532646d3237306574757a3778797877657539"], - ["b3534201cfb1cd8dbf69b8250c18ef41294ca979", null, "902b6565a1c44e7e7a080571af1dd774697cc126f1fc0435d3cdbf868783e9fb4620df4bf175cbf2c3e36f", "05f61273a7201295332fee4579474534809a0aeb817a2bc0594166ad7a462067712533b6eec0fa2d1be99f", "7531383863733339306532376632346877676468396573756532796b73386c3230743271367864686a39646d32396c3877376d34726438336473706d72743271336435746e36376e367379736e7438306872387a676e6377376b38386735306e6376367874653835676b676e707a79647037747367677166343533723464787164356d6b78757561377938343871747a65383365763777366a676d6a7738363935793475337a7778326671637a6b6875687938356a6764746a72343339366a6d6467643937383768663739783634786b32646e6a70"], - [null, "e8c7203d996af7d477083756d59af80d06a745f4", null, "4ea7d6b3dfa338192af06cbbf47ad405715bc7832bedb1466217dc0d93314de9f3c25eec89f9a21bfe0e93", "753179763478336d786e3364787a3033746b76336575646861683878637838366d6633717667326a397a6c61656a676b716c366633797a6d6e7479387576363868366774616a38677a676c71676d7775723061646b686765307671636e74617668393335307437387a79637772346c363463746633716e3934637472797338356e6c3476306c77383270767173"], - [null, null, "02f1536b622c01346742d8f90e9d4ff39137f1bebe6e23ad9971776b3372702494cc08951eef032b35350f", null, "753135716632787236373076337971796b6374397663716c7935687079766b6d68386b3371636c7135367664686d7030386336717a30726c6e763467307168613975736e6c37336b713539376838763363377274717765303575326836637035706374767a7a346c7463"], - [null, "183e31d49f25c9a138f49b1a537edcf04be34a98", "3246b59a5b492dab1855cc176bddfa28418f11f97f7b361cc3e8834b2c30d2a1717df323ef98ea7de71d2e", "ab6d26252c521547049de208283d96278bb221a6874cb5a86af1d3f8b3db3fbee3dbefedcb2c71e3ca1ead", "753130657a616879367071307034687a65703666376564706775376c67777530796372366c6c6463796a36713530356e67617672706b766534357461396861776571666c3361763768323977346d633777636a7a3871686a797132726e6d6861387271716b34616d3861713461346a6d743263326e6a37746368653765647571367968613536766b73343971706c77786b707761333666676864367036336c796763706339796774773964617630786366326d787270387530367474683468676732383937307368796468637871796a79726b3235"], - [null, null, "970dc3450d34554141d356cb548056279c57708fa73bd16ffe9a2e24ea694898a7b8af1b0ff92585d02623", "0414bb62b86149ee731851f27d532ac0361169da46e6d53d19d3dfd07a5bae22969922d8d0af7dc1e13bae", "753163723077393538346b6133676d6a70687a63636b306736367676786e38723266647566636a707477367534346165327379756b6b6d7a7763716673776b65776e7a6d7a7a7571736c73793733637178706d68336d797967756e6b6e6d73676d746c7a716b7436686e7461687973676a767a77307133707a647865757666747978647a6870726873666a6b3374686e686d706730706834666d36386b7035386d653336386464657066647671356e77726c"], - [null, "098b79535e790fe53e29fef2b3766697ac32b4f4", "a8a8797c1ba69f78672affa65b943975026931ea628431f0991e744872ac9f36946f5dcd6851a0b5af29cf", "678ab0079bea28bf165c1ab976a2a58c18a7811ca2ad0ad649e876273d04325da6ca53cdb83c111e8e4394", "7531676e333576786d3030666b713430636c647a76717372767037336e36726b383036306e6b39686d6c77376535323070346a73757265756b6e757738726c6a7166336e71766130347434326b6e66753071716e39666c6830676e707a766d673868653070747272326e6c38306a787a666178723039656739323035727273727265737a7339306c63633876737561636836773535777334337738637577716d3768736e387234343361617370366d6533327177346c7639666533393978333370783861767865636b656d763976327867366b6e37"], - [null, null, "3509c9e069e89fe501d97622c283ac98923da2d7e6eb346b4bafa67865e1e6dae7cf213b1ea3648dc09b48", null, "753165686465736a6a647370336839376a787a6361766b686433327032706173306a6b333274783577736d707a6a6c35783534306835353335636c6677686b6b686c3367716370726d7779653279793239306a66706378716a71756c616a766a76357571786e7463656e"], - [null, "30d069896cff30eb414f727b89e001afa2fb8dc3", "55bc46aea6f60c1d61915640029b2af6334d7d27e1c47a248ab47c9fbe5d2d7bb5818739f062e37136654c", null, "7531766e63346a336e6a6b377174706a65767764743877347a356e30376b3670363277396a673977796d6a6c7530776d766d7570357579656a61613736646b646778797337653661646e7865636678636e6c39306571366539723035647379353274363976653961756e6b376a773270337477726175686e6c3638346d6e77336332757968616a366c70346c33"], - [null, null, "5c26a8117729334a957ca7941d47b2ce7040e844fa9882c25bfd2fcf51fa8ab21376f5300d0123f5703e9e", null, "75317279687461366d73356a617375396e76653232396d7639383664677a39366a6c37357232716c6d78797061363775657276373834727235306663677567766b646767327773726e7877737378756c77306c7a387735373970746a3239777567383867673577337a73"] + [null, "7a8f739a2d9e945b0ce152a8049e294c4d6e66b1", null, "dcb1d2a37762148db4cee3bbf19fb1ec05891894b13801c622ba6a90faf1119f8224ae3985c6abd3b7bbae", "75316532386638787a6e656d676574797872647a6b66676a756773667839646b713274686e657a65396c333474707674706d656a656774643567686b7768676a7268736466646e74336b34736632757939656138637461756d7a7075646c657a356667756c77716b70753566766a77796374747a79646c383664373434613430617175747a687a7674797a6e68"], + ["b3534201cfb1cd8dbf69b8250c18ef41294ca979", null, "902b6565a1c44e7e7a080571af1dd774697cc126f1fc0435d3cdbf868783e9fb4620df4bf175cbf2c3e36f", "05f61273a7201295332fee4579474534809a0aeb817a2bc0594166ad7a462067712533b6eec0fa2d1be99f", "75313371733278796b66737464343332777076366368367336636b683473346833736372746435686b6179367277366a6e3667656e3734726d76636136357775736771653637716d6b6b667a79686c6b7767383071796a33726363616e68356667377a73393032793234676e3271796636706b636363686730356a7a70337972666e3470753861746538673771397239737465767832383434357235776e3378333570663771713332346e746878747a6377786576796661346c326d326d327873376564766570396674613476747776686b617878"], + [null, "e8c7203d996af7d477083756d59af80d06a745f4", null, "4ea7d6b3dfa338192af06cbbf47ad405715bc7832bedb1466217dc0d93314de9f3c25eec89f9a21bfe0e93", "75317270776b64357837746534657a636d6c716172676b66336372737066716b686d787766737170713032346a6173733267373465347233367a70353071737333766863743732736163687573306b37303578796768756c726a786364777764617130716a6e6e737366326676616b7a7a386634367077387263613933366665796566366d6c36657137776c6c"], + [null, null, "02f1536b622c01346742d8f90e9d4ff39137f1bebe6e23ad9971776b3372702494cc08951eef032b35350f", null, "7531396468786d38386776637739747774767a6b7537637a376a753372767075356a766832637138676d38716465766e6c34657365793833667a7239796d666133676a6d6d6b3472786a3279703838677478646b71676e6a366e6e717974667568303875796335667572"], + [null, "183e31d49f25c9a138f49b1a537edcf04be34a98", "3246b59a5b492dab1855cc176bddfa28418f11f97f7b361cc3e8834b2c30d2a1717df323ef98ea7de71d2e", "ab6d26252c521547049de208283d96278bb221a6874cb5a86af1d3f8b3db3fbee3dbefedcb2c71e3ca1ead", "75313563327972666a7774743636336e713068707173683678746a793238387a7476616375616c37336d666675723338336d7465706339687278743374703465613568373830706733686b35756a326775393770326c756d39716a6836327872613763336879366e6471327877686737657138713736766632386333326437766d6c337a323934767438656374636c773672307032336e64703578647a666578633971773065777572796e6a353235736b78376d306a756b636a7265616b6a3261703332376b6a7172767567656435667930737a79"], + [null, null, "970dc3450d34554141d356cb548056279c57708fa73bd16ffe9a2e24ea694898a7b8af1b0ff92585d02623", "0414bb62b86149ee731851f27d532ac0361169da46e6d53d19d3dfd07a5bae22969922d8d0af7dc1e13bae", "75317a6467397a376c7732713037357977396e306a376668387279756a73726a727237347a71783939337463736874666d6d3271786b74763372303438653774723471356a38736665703367396e76387770786639767472336a7a6e6d6d35367a3775706a6530356b7a766d75726d706371703034633033377a32646833356364383232357874336b34376e7a6668327974737630376d337438676433337035723276376b66656739343571376a63306768"], + [null, "098b79535e790fe53e29fef2b3766697ac32b4f4", "a8a8797c1ba69f78672affa65b943975026931ea628431f0991e744872ac9f36946f5dcd6851a0b5af29cf", "678ab0079bea28bf165c1ab976a2a58c18a7811ca2ad0ad649e876273d04325da6ca53cdb83c111e8e4394", "7531796a7733366d7a777a346a643879746e726436676b68376179676d656a3272746c716733766a397965656866646b3233356a657336727170666a6c777167333776346d653575676a6c7a72646e68676c383872726c6567383378386130716d77797a7936393872387675636e346877616772367163657a7373663663683074373466633068766e366d373737687037353761766632636b7a63333239357033323430716c7675707964656c37336c377163746e343063796b357536736573617772367a6d6b746c6a6678687163633765773468"], + [null, null, "3509c9e069e89fe501d97622c283ac98923da2d7e6eb346b4bafa67865e1e6dae7cf213b1ea3648dc09b48", null, "753171786b796d6b68647a6372727a6c79346672717563646b66736e6a377776776c716575306b3466337472706e657a3476777a75686b64616a6b356537363437346d6a34396b75653978396866776566386d34377363633861703933686e6773657567333864706371"], + [null, "30d069896cff30eb414f727b89e001afa2fb8dc3", "55bc46aea6f60c1d61915640029b2af6334d7d27e1c47a248ab47c9fbe5d2d7bb5818739f062e37136654c", null, "75316433726b71777a396b37346b7475766c746e32746d746a36676b6c6739336877733937797473337a75363038766b76673363327973686d6d3330713668386b6434727433733076703475616a776668396137356538613837306e39346c6b70657835617337716e77333436346e7261747563356e35793575766e7a7666326d3466656a687a6576686e306d"], + [null, null, "5c26a8117729334a957ca7941d47b2ce7040e844fa9882c25bfd2fcf51fa8ab21376f5300d0123f5703e9e", null, "75316166617430647574617379666b736161766d34726c336178716e75786c777437363573393476397a716a7430397a793633646c356d6d7970397835636b7672756c6d647134636b6a337272763766396c37756e78666c306438723635383234746773677276673071"] ] +