@@ -4,7 +4,6 @@ use std::collections::hash_map::Entry;
44use std:: collections:: { BTreeMap , HashMap , HashSet } ;
55use std:: env;
66use std:: fmt:: Debug ;
7- use std:: fs:: File ;
87#[ cfg( feature = "masp-tx-gen" ) ]
98use std:: ops:: Deref ;
109use std:: path:: PathBuf ;
@@ -44,9 +43,7 @@ use masp_primitives::transaction::{
4443 TransparentAddress , Unauthorized ,
4544} ;
4645use masp_primitives:: zip32:: { ExtendedFullViewingKey , ExtendedSpendingKey } ;
47- use masp_proofs:: bellman:: groth16:: {
48- prepare_verifying_key, PreparedVerifyingKey ,
49- } ;
46+ use masp_proofs:: bellman:: groth16:: PreparedVerifyingKey ;
5047use masp_proofs:: bls12_381:: Bls12 ;
5148use masp_proofs:: prover:: LocalTxProver ;
5249use masp_proofs:: sapling:: SaplingVerificationContext ;
@@ -90,62 +87,37 @@ pub const OUTPUT_NAME: &str = "masp-output.params";
9087/// Convert circuit name
9188pub const CONVERT_NAME : & str = "masp-convert.params" ;
9289
93- enum MaspParams {
94- Spend ,
95- Convert ,
96- Output ,
97- }
98-
99- /// Generic helper to load Sapling params.
100- fn load_params ( name : MaspParams ) -> (
101- masp_proofs:: bellman:: groth16:: Parameters < Bls12 > ,
102- masp_proofs:: bellman:: groth16:: PreparedVerifyingKey < Bls12 > ,
90+ fn load_pvks ( ) -> (
91+ PreparedVerifyingKey < Bls12 > ,
92+ PreparedVerifyingKey < Bls12 > ,
93+ PreparedVerifyingKey < Bls12 > ,
10394) {
104- let params_name = match name {
105- MaspParams :: Spend => SPEND_NAME ,
106- MaspParams :: Convert => CONVERT_NAME ,
107- MaspParams :: Output => OUTPUT_NAME ,
108- } ;
109-
11095 let params_dir = get_params_dir ( ) ;
111- let params_path = params_dir. join ( params_name) ;
112- if !params_path. exists ( ) {
113- #[ cfg( feature = "masp_proofs/download-params" ) ]
114- masp_proofs:: download_parameters ( )
115- . expect ( "MASP parameters not present or downloadable" ) ;
116- #[ cfg( not( feature = "masp_proofs/download-params" ) ) ]
117- panic ! ( "MASP parameters not present or downloadable" ) ;
118- }
119- let param_f = File :: open ( params_path) . unwrap ( ) ;
120- let params =
121- masp_proofs:: bellman:: groth16:: Parameters :: read ( & param_f, false )
122- . unwrap ( ) ;
123- let vk = prepare_verifying_key ( & params. vk ) ;
124- ( params, vk)
125- }
126-
127- /// Load Sapling spend params.
128- pub fn load_spend_params ( ) -> (
129- masp_proofs:: bellman:: groth16:: Parameters < Bls12 > ,
130- masp_proofs:: bellman:: groth16:: PreparedVerifyingKey < Bls12 > ,
131- ) {
132- load_params ( MaspParams :: Spend )
133- }
96+ let [ spend_path, convert_path, output_path] =
97+ [ SPEND_NAME , CONVERT_NAME , OUTPUT_NAME ] . map ( |p| params_dir. join ( p) ) ;
13498
135- /// Load Sapling convert params.
136- pub fn load_convert_params ( ) -> (
137- masp_proofs:: bellman:: groth16:: Parameters < Bls12 > ,
138- masp_proofs:: bellman:: groth16:: PreparedVerifyingKey < Bls12 > ,
139- ) {
140- load_params ( MaspParams :: Convert )
141- }
142-
143- /// Load Sapling output params.
144- pub fn load_output_params ( ) -> (
145- masp_proofs:: bellman:: groth16:: Parameters < Bls12 > ,
146- masp_proofs:: bellman:: groth16:: PreparedVerifyingKey < Bls12 > ,
147- ) {
148- load_params ( MaspParams :: Output )
99+ if !spend_path. exists ( ) || !convert_path. exists ( ) || !output_path. exists ( ) {
100+ let paths = masp_proofs:: download_masp_parameters ( None ) . expect (
101+ "MASP parameters were not present, expected the download to \
102+ succeed",
103+ ) ;
104+ if paths. spend != spend_path
105+ || paths. convert != convert_path
106+ || paths. output != output_path
107+ {
108+ panic ! (
109+ "unrecoverable: downloaded missing masp params, but to an \
110+ unfamiliar path"
111+ )
112+ }
113+ }
114+ // size and blake2b checked here
115+ let params = masp_proofs:: load_parameters (
116+ spend_path. as_path ( ) ,
117+ output_path. as_path ( ) ,
118+ convert_path. as_path ( ) ,
119+ ) ;
120+ ( params. spend_vk , params. convert_vk , params. output_vk )
149121}
150122
151123/// check_spend wrapper
@@ -277,9 +249,7 @@ pub fn verify_shielded_tx(transaction: &Transaction) -> bool {
277249
278250 tracing:: info!( "sighash computed" ) ;
279251
280- let ( _, spend_pvk) = load_spend_params ( ) ;
281- let ( _, convert_pvk) = load_convert_params ( ) ;
282- let ( _, output_pvk) = load_output_params ( ) ;
252+ let ( spend_pvk, convert_pvk, output_pvk) = load_pvks ( ) ;
283253
284254 let mut ctx = SaplingVerificationContext :: new ( true ) ;
285255 let spends_valid = sapling_bundle. shielded_spends . iter ( ) . all ( |spend| {
@@ -365,7 +335,7 @@ impl<P1, R1, N1>
365335
366336/// Abstracts platform specific details away from the logic of shielded pool
367337/// operations.
368- #[ async_trait( ?Send ) ]
338+ #[ async_trait( ? Send ) ]
369339pub trait ShieldedUtils :
370340 Sized + BorshDeserialize + BorshSerialize + Default + Clone
371341{
@@ -1546,3 +1516,105 @@ fn convert_amount(
15461516 . expect ( "invalid value for amount" ) ;
15471517 ( asset_type, amount)
15481518}
1519+
1520+ mod tests {
1521+ /// quick and dirty test. will fail on size check
1522+ #[ test]
1523+ #[ should_panic( expected = "parameter file size is not correct" ) ]
1524+ fn test_wrong_masp_params ( ) {
1525+ use std:: io:: Write ;
1526+
1527+ use super :: { CONVERT_NAME , OUTPUT_NAME , SPEND_NAME } ;
1528+
1529+ let tempdir = tempfile:: tempdir ( )
1530+ . expect ( "expected a temp dir" )
1531+ . into_path ( ) ;
1532+ let fake_params_paths =
1533+ [ SPEND_NAME , CONVERT_NAME , OUTPUT_NAME ] . map ( |p| tempdir. join ( p) ) ;
1534+ for path in fake_params_paths {
1535+ let mut f =
1536+ std:: fs:: File :: create ( path) . expect ( "expected a temp file" ) ;
1537+ f. write_all ( b"fake params" )
1538+ . expect ( "expected a writable temp file" ) ;
1539+ f. sync_all ( )
1540+ . expect ( "expected a writable temp file (on sync)" ) ;
1541+ }
1542+
1543+ std:: env:: set_var ( super :: ENV_VAR_MASP_PARAMS_DIR , tempdir. as_os_str ( ) ) ;
1544+ // should panic here
1545+ super :: load_pvks ( ) ;
1546+ }
1547+
1548+ /// a more involved test, using dummy parameters with the right
1549+ /// size but the wrong hash.
1550+ #[ test]
1551+ #[ should_panic( expected = "parameter file is not correct" ) ]
1552+ fn test_wrong_masp_params_hash ( ) {
1553+ use masp_primitives:: ff:: PrimeField ;
1554+ use masp_proofs:: bellman:: groth16:: {
1555+ generate_random_parameters, Parameters ,
1556+ } ;
1557+ use masp_proofs:: bellman:: { Circuit , ConstraintSystem , SynthesisError } ;
1558+ use masp_proofs:: bls12_381:: { Bls12 , Scalar } ;
1559+
1560+ use super :: { CONVERT_NAME , OUTPUT_NAME , SPEND_NAME } ;
1561+
1562+ struct FakeCircuit < E : PrimeField > {
1563+ x : E ,
1564+ }
1565+
1566+ impl < E : PrimeField > Circuit < E > for FakeCircuit < E > {
1567+ fn synthesize < CS : ConstraintSystem < E > > (
1568+ self ,
1569+ cs : & mut CS ,
1570+ ) -> Result < ( ) , SynthesisError > {
1571+ let x = cs. alloc ( || "x" , || Ok ( self . x ) ) . unwrap ( ) ;
1572+ cs. enforce (
1573+ || {
1574+ "this is an extra long constraint name so that rustfmt \
1575+ is ok with wrapping the params of enforce()"
1576+ } ,
1577+ |lc| lc + x,
1578+ |lc| lc + x,
1579+ |lc| lc + x,
1580+ ) ;
1581+ Ok ( ( ) )
1582+ }
1583+ }
1584+
1585+ let dummy_circuit = FakeCircuit { x : Scalar :: zero ( ) } ;
1586+ let mut rng = rand:: thread_rng ( ) ;
1587+ let fake_params: Parameters < Bls12 > =
1588+ generate_random_parameters ( dummy_circuit, & mut rng)
1589+ . expect ( "expected to generate fake params" ) ;
1590+
1591+ let tempdir = tempfile:: tempdir ( )
1592+ . expect ( "expected a temp dir" )
1593+ . into_path ( ) ;
1594+ // TODO: get masp to export these consts
1595+ let fake_params_paths = [
1596+ ( SPEND_NAME , 49848572u64 ) ,
1597+ ( CONVERT_NAME , 22570940u64 ) ,
1598+ ( OUTPUT_NAME , 16398620u64 ) ,
1599+ ]
1600+ . map ( |( p, s) | ( tempdir. join ( p) , s) ) ;
1601+ for ( path, size) in fake_params_paths {
1602+ let mut f =
1603+ std:: fs:: File :: create ( path) . expect ( "expected a temp file" ) ;
1604+ fake_params
1605+ . write ( & mut f)
1606+ . expect ( "expected a writable temp file" ) ;
1607+ // the dummy circuit has one constraint, and therefore its
1608+ // params should always be smaller than the large masp
1609+ // circuit params. so this truncate extends the file, and
1610+ // extra bytes at the end do not make it invalid.
1611+ f. set_len ( size) . expect ( "expected to truncate the temp file" ) ;
1612+ f. sync_all ( )
1613+ . expect ( "expected a writable temp file (on sync)" ) ;
1614+ }
1615+
1616+ std:: env:: set_var ( super :: ENV_VAR_MASP_PARAMS_DIR , tempdir. as_os_str ( ) ) ;
1617+ // should panic here
1618+ super :: load_pvks ( ) ;
1619+ }
1620+ }
0 commit comments