@@ -71,8 +71,8 @@ describe('confidential', () => {
7171 }
7272 } ) ;
7373
74- it ( 'unblind' , ( ) => {
75- fixtures . valid . unblind . forEach ( async ( f : any ) => {
74+ it ( 'unblind' , async ( ) => {
75+ for ( const f of fixtures . valid . unblind as any [ ] ) {
7676 const out : TxOutput = {
7777 value : f . valueCommitment ,
7878 asset : f . assetGenerator ,
@@ -97,7 +97,79 @@ describe('confidential', () => {
9797 unblindProof . assetBlindingFactor . toString ( 'hex' ) ,
9898 f . expected . assetBlindingFactor ,
9999 ) ;
100- } ) ;
100+ }
101+ } ) ;
102+
103+ it ( 'isUnblindedAssetValid' , async ( ) => {
104+ for ( const f of fixtures . valid . rangeproof as any [ ] ) {
105+ const zkpLib = await secp256k1 ( ) ;
106+ const confidential = new Confidential ( zkpLib ) ;
107+
108+ const asset = Buffer . from ( f . asset , 'hex' ) ;
109+ const assetCommitment = Buffer . from ( f . assetCommitment , 'hex' ) ;
110+ const valueCommitment = Buffer . from ( f . valueCommitment , 'hex' ) ;
111+ const valueBlindingFactor = Buffer . from ( f . valueBlindingFactor , 'hex' ) ;
112+ const assetBlindingFactor = Buffer . from ( f . assetBlindingFactor , 'hex' ) ;
113+ const scriptPubkey = Buffer . from ( f . scriptPubkey , 'hex' ) ;
114+
115+ const nonce = confidential . nonceHash (
116+ Buffer . from ( f . blindingPubkey , 'hex' ) ,
117+ Buffer . from ( f . ephemeralPrivkey , 'hex' ) ,
118+ ) ;
119+
120+ const buildOutput = ( proofAsset : Buffer ) : TxOutput => ( {
121+ value : valueCommitment ,
122+ asset : assetCommitment ,
123+ script : scriptPubkey ,
124+ // a range proof valid for the output's value/asset commitments whose
125+ // embedded message claims `proofAsset`
126+ rangeProof : confidential . rangeProof (
127+ f . value ,
128+ proofAsset ,
129+ valueCommitment ,
130+ assetCommitment ,
131+ valueBlindingFactor ,
132+ assetBlindingFactor ,
133+ nonce ,
134+ scriptPubkey ,
135+ '1' ,
136+ '0' ,
137+ '36' ,
138+ ) ,
139+ nonce : Buffer . alloc ( 0 ) ,
140+ } ) ;
141+
142+ // the asset the output actually commits to is accepted, and unblinding
143+ // succeeds
144+ const validOut = buildOutput ( asset ) ;
145+ const unblinded = confidential . unblindOutputWithNonce ( validOut , nonce ) ;
146+ assert . strictEqual (
147+ confidential . isUnblindedAssetValid ( validOut , unblinded ) ,
148+ true ,
149+ ) ;
150+
151+ // an asset id different from the one the output commits to is rejected
152+ const otherAsset = Buffer . from ( f . asset , 'hex' ) ;
153+ otherAsset [ 0 ] ^= 0x01 ;
154+ const forgedOut = buildOutput ( otherAsset ) ;
155+
156+ assert . strictEqual (
157+ confidential . isUnblindedAssetValid ( forgedOut , {
158+ value : f . value ,
159+ valueBlindingFactor,
160+ asset : otherAsset ,
161+ assetBlindingFactor,
162+ } ) ,
163+ false ,
164+ ) ;
165+
166+ // unblinding the forged output must throw instead of returning a result
167+ // with a spoofed asset
168+ assert . throws (
169+ ( ) => confidential . unblindOutputWithNonce ( forgedOut , nonce ) ,
170+ / U n b l i n d e d a n d o u t p u t a s s e t / ,
171+ ) ;
172+ }
101173 } ) ;
102174
103175 it ( 'rangeProofInfo' , async ( ) => {
0 commit comments