@@ -150,6 +150,42 @@ function buildOts(digest: Buffer, subItems: Buffer[]): Buffer {
150150const EVENT_ID = 'e71c6ea722987debdb60f81f9ea4f604b5ac0664120dd64fb9d23abc4ec7c323'
151151const DIGEST = Buffer . from ( EVENT_ID , 'hex' )
152152
153+ const BITCOIN_ATTESTATION_810391 = bitcoinAttestation ( 810391 )
154+ const BITCOIN_ATTESTATION_1 = bitcoinAttestation ( 1 )
155+ const BITCOIN_ATTESTATION_42 = bitcoinAttestation ( 42 )
156+ const PENDING_ATTESTATION_DEFAULT = pendingAttestation ( 'https://a.pool.opentimestamps.org' )
157+
158+ const MINIMAL_BITCOIN_OTS = buildOts ( DIGEST , [ BITCOIN_ATTESTATION_810391 ] )
159+
160+ const OTS_WITH_APPEND_OP = ( ( ) => {
161+ const opAppend = Buffer . concat ( [ Buffer . from ( [ OP_APPEND ] ) , writeVarBytes ( Buffer . from ( [ 0xde , 0xad , 0xbe , 0xef ] ) ) ] )
162+ const tree = Buffer . concat ( [ opAppend , BITCOIN_ATTESTATION_1 ] )
163+ return buildOts ( DIGEST , [ tree ] )
164+ } ) ( )
165+
166+ const OTS_PENDING_AND_BITCOIN = buildOts ( DIGEST , [ PENDING_ATTESTATION_DEFAULT , BITCOIN_ATTESTATION_42 ] )
167+
168+ const OTS_LITECOIN_AND_UNKNOWN = buildOts ( DIGEST , [ litecoinAttestation ( 2500000 ) , unknownAttestation ( Buffer . from ( [ 1 , 2 , 3 ] ) ) ] )
169+
170+ const OTS_ETHEREUM = buildOts ( DIGEST , [ ethereumAttestation ( 18_000_000 ) ] )
171+
172+ const OTS_PREPEND = ( ( ) => {
173+ const prepend = Buffer . concat ( [ Buffer . from ( [ OP_PREPEND ] ) , writeVarBytes ( Buffer . from ( [ 0x01 ] ) ) ] )
174+ return buildOts ( DIGEST , [ Buffer . concat ( [ prepend , bitcoinAttestation ( 4 ) ] ) ] )
175+ } ) ( )
176+
177+ const OTS_REVERSE_HEXLIFY = ( ( ) => {
178+ const revThenHex = Buffer . concat ( [ Buffer . from ( [ OP_REVERSE ] ) , Buffer . from ( [ OP_HEXLIFY ] ) , bitcoinAttestation ( 5 ) ] )
179+ return buildOts ( DIGEST , [ revThenHex ] )
180+ } ) ( )
181+
182+ const OTS_TRUNCATED_ATTESTATION = ( ( ) => {
183+ const broken = Buffer . concat ( [ Buffer . from ( [ TAG_ATTESTATION ] ) , BITCOIN_TAG , writeVarUint ( 0 ) ] )
184+ return buildOts ( DIGEST , [ broken ] )
185+ } ) ( )
186+
187+ const VALID_PROOF_BASE64 = MINIMAL_BITCOIN_OTS . toString ( 'base64' )
188+
153189describe ( 'OtsReader' , ( ) => {
154190 it ( 'readBytes rejects a negative length' , ( ) => {
155191 const r = new OtsReader ( Buffer . from ( [ 1 , 2 , 3 ] ) )
@@ -166,9 +202,7 @@ describe('OtsReader', () => {
166202describe ( 'NIP-03 — OpenTimestamps' , ( ) => {
167203 describe ( 'parseOtsFile' , ( ) => {
168204 it ( 'parses a minimal proof with a single bitcoin attestation' , ( ) => {
169- const buf = buildOts ( DIGEST , [ bitcoinAttestation ( 810391 ) ] )
170-
171- const result = expectSuccess ( parseOtsFile ( buf ) )
205+ const result = expectSuccess ( parseOtsFile ( MINIMAL_BITCOIN_OTS ) )
172206
173207 expect ( result . summary . version ) . to . equal ( 1 )
174208 expect ( result . summary . fileHashOp ) . to . equal ( 'sha256' )
@@ -178,27 +212,19 @@ describe('NIP-03 — OpenTimestamps', () => {
178212 } )
179213
180214 it ( 'parses a proof with ops that wrap an attestation' , ( ) => {
181- const opAppend = Buffer . concat ( [ Buffer . from ( [ OP_APPEND ] ) , writeVarBytes ( Buffer . from ( [ 0xde , 0xad , 0xbe , 0xef ] ) ) ] )
182- const tree = Buffer . concat ( [ opAppend , bitcoinAttestation ( 1 ) ] )
183- const buf = buildOts ( DIGEST , [ tree ] )
184-
185- const result = expectSuccess ( parseOtsFile ( buf ) )
215+ const result = expectSuccess ( parseOtsFile ( OTS_WITH_APPEND_OP ) )
186216
187217 expect ( result . summary . attestations . map ( ( a ) => a . kind ) ) . to . deep . equal ( [ 'bitcoin' ] )
188218 } )
189219
190220 it ( 'parses a proof with multiple attestations (pending + bitcoin)' , ( ) => {
191- const buf = buildOts ( DIGEST , [ pendingAttestation ( 'https://a.pool.opentimestamps.org' ) , bitcoinAttestation ( 42 ) ] )
192-
193- const result = expectSuccess ( parseOtsFile ( buf ) )
221+ const result = expectSuccess ( parseOtsFile ( OTS_PENDING_AND_BITCOIN ) )
194222 const kinds = result . summary . attestations . map ( ( a ) => a . kind ) . sort ( )
195223 expect ( kinds ) . to . deep . equal ( [ 'bitcoin' , 'pending' ] )
196224 } )
197225
198226 it ( 'classifies litecoin and unknown attestations correctly' , ( ) => {
199- const buf = buildOts ( DIGEST , [ litecoinAttestation ( 2500000 ) , unknownAttestation ( Buffer . from ( [ 1 , 2 , 3 ] ) ) ] )
200-
201- const result = expectSuccess ( parseOtsFile ( buf ) )
227+ const result = expectSuccess ( parseOtsFile ( OTS_LITECOIN_AND_UNKNOWN ) )
202228 const kinds = result . summary . attestations . map ( ( a ) => a . kind ) . sort ( )
203229 expect ( kinds ) . to . deep . equal ( [ 'litecoin' , 'unknown' ] )
204230 } )
@@ -210,28 +236,26 @@ describe('NIP-03 — OpenTimestamps', () => {
210236 } )
211237
212238 it ( 'rejects an unsupported file hash op' , ( ) => {
213- const parts = [ MAGIC , writeVarUint ( 1 ) , Buffer . from ( [ 0x55 ] ) , Buffer . alloc ( 32 ) , bitcoinAttestation ( 1 ) ]
239+ const parts = [ MAGIC , writeVarUint ( 1 ) , Buffer . from ( [ 0x55 ] ) , Buffer . alloc ( 32 ) , BITCOIN_ATTESTATION_1 ]
214240 const buf = Buffer . concat ( parts )
215241 const result = expectFailure ( parseOtsFile ( buf ) )
216242 expect ( result . reason ) . to . match ( / u n s u p p o r t e d f i l e h a s h o p / )
217243 } )
218244
219245 it ( 'rejects an unsupported ots file version' , ( ) => {
220- const parts = [ MAGIC , writeVarUint ( 2 ) , Buffer . from ( [ OP_SHA256 ] ) , DIGEST , bitcoinAttestation ( 1 ) ]
246+ const parts = [ MAGIC , writeVarUint ( 2 ) , Buffer . from ( [ OP_SHA256 ] ) , DIGEST , BITCOIN_ATTESTATION_1 ]
221247 const buf = Buffer . concat ( parts )
222248 const result = expectFailure ( parseOtsFile ( buf ) )
223249 expect ( result . reason ) . to . match ( / u n s u p p o r t e d o t s v e r s i o n / )
224250 } )
225251
226252 it ( 'rejects truncated proofs without crashing' , ( ) => {
227- const good = buildOts ( DIGEST , [ bitcoinAttestation ( 1 ) ] )
228- const truncated = good . subarray ( 0 , good . length - 3 )
253+ const truncated = MINIMAL_BITCOIN_OTS . subarray ( 0 , MINIMAL_BITCOIN_OTS . length - 3 )
229254 expectFailure ( parseOtsFile ( truncated ) )
230255 } )
231256
232257 it ( 'rejects proofs with trailing garbage' , ( ) => {
233- const good = buildOts ( DIGEST , [ bitcoinAttestation ( 1 ) ] )
234- const withGarbage = Buffer . concat ( [ good , Buffer . from ( [ 0x00 , 0x11 , 0x22 ] ) ] )
258+ const withGarbage = Buffer . concat ( [ MINIMAL_BITCOIN_OTS , Buffer . from ( [ 0x00 , 0x11 , 0x22 ] ) ] )
235259 const result = expectFailure ( parseOtsFile ( withGarbage ) )
236260 expect ( result . reason ) . to . match ( / t r a i l i n g b y t e s / )
237261 } )
@@ -252,7 +276,7 @@ describe('NIP-03 — OpenTimestamps', () => {
252276
253277 it ( 'parses sha1 file digest (20-byte) proofs' , ( ) => {
254278 const digest = Buffer . alloc ( 20 , 0xab )
255- const buf = buildOtsWithFileHashOp ( OP_SHA1 , digest , [ bitcoinAttestation ( 1 ) ] )
279+ const buf = buildOtsWithFileHashOp ( OP_SHA1 , digest , [ BITCOIN_ATTESTATION_1 ] )
256280 const result = expectSuccess ( parseOtsFile ( buf ) )
257281 expect ( result . summary . fileHashOp ) . to . equal ( 'sha1' )
258282 expect ( result . summary . digest ) . to . equal ( digest . toString ( 'hex' ) )
@@ -273,31 +297,24 @@ describe('NIP-03 — OpenTimestamps', () => {
273297 } )
274298
275299 it ( 'parses prepend binary op in the commitment tree' , ( ) => {
276- const prepend = Buffer . concat ( [ Buffer . from ( [ OP_PREPEND ] ) , writeVarBytes ( Buffer . from ( [ 0x01 ] ) ) ] )
277- const buf = buildOts ( DIGEST , [ Buffer . concat ( [ prepend , bitcoinAttestation ( 4 ) ] ) ] )
278- const result = expectSuccess ( parseOtsFile ( buf ) )
300+ const result = expectSuccess ( parseOtsFile ( OTS_PREPEND ) )
279301 expect ( result . summary . attestations . some ( ( a ) => a . kind === 'bitcoin' ) ) . to . equal ( true )
280302 } )
281303
282304 it ( 'parses reverse and hexlify unary ops wrapping an attestation' , ( ) => {
283- const revThenHex = Buffer . concat ( [ Buffer . from ( [ OP_REVERSE ] ) , Buffer . from ( [ OP_HEXLIFY ] ) , bitcoinAttestation ( 5 ) ] )
284- const buf = buildOts ( DIGEST , [ revThenHex ] )
285- const result = expectSuccess ( parseOtsFile ( buf ) )
305+ const result = expectSuccess ( parseOtsFile ( OTS_REVERSE_HEXLIFY ) )
286306 expect ( result . summary . attestations [ 0 ] . kind ) . to . equal ( 'bitcoin' )
287307 } )
288308
289309 it ( 'classifies ethereum block header attestations' , ( ) => {
290- const buf = buildOts ( DIGEST , [ ethereumAttestation ( 18_000_000 ) ] )
291- const result = expectSuccess ( parseOtsFile ( buf ) )
310+ const result = expectSuccess ( parseOtsFile ( OTS_ETHEREUM ) )
292311 const eth = result . summary . attestations . find ( ( a ) => a . kind === 'ethereum' )
293312 expect ( eth ) . to . exist
294313 expect ( eth ?. height ) . to . equal ( 18_000_000 )
295314 } )
296315
297316 it ( 'treats a truncated bitcoin attestation payload as height-less' , ( ) => {
298- const broken = Buffer . concat ( [ Buffer . from ( [ TAG_ATTESTATION ] ) , BITCOIN_TAG , writeVarUint ( 0 ) ] )
299- const buf = buildOts ( DIGEST , [ broken ] )
300- const result = expectSuccess ( parseOtsFile ( buf ) )
317+ const result = expectSuccess ( parseOtsFile ( OTS_TRUNCATED_ATTESTATION ) )
301318 expect ( result . summary . attestations [ 0 ] ) . to . include ( { kind : 'bitcoin' } )
302319 expect ( result . summary . attestations [ 0 ] . height ) . to . equal ( undefined )
303320 } )
@@ -343,14 +360,12 @@ describe('NIP-03 — OpenTimestamps', () => {
343360 } )
344361
345362 describe ( 'validateOtsProof' , ( ) => {
346- const validProof = buildOts ( DIGEST , [ bitcoinAttestation ( 810391 ) ] ) . toString ( 'base64' )
347-
348363 it ( 'accepts a well-formed bitcoin-anchored proof whose digest matches' , ( ) => {
349- expect ( validateOtsProof ( validProof , EVENT_ID ) ) . to . equal ( undefined )
364+ expect ( validateOtsProof ( VALID_PROOF_BASE64 , EVENT_ID ) ) . to . equal ( undefined )
350365 } )
351366
352367 it ( 'accepts uppercase hex target ids and normalizes them' , ( ) => {
353- expect ( validateOtsProof ( validProof , EVENT_ID . toUpperCase ( ) ) ) . to . equal ( undefined )
368+ expect ( validateOtsProof ( VALID_PROOF_BASE64 , EVENT_ID . toUpperCase ( ) ) ) . to . equal ( undefined )
354369 } )
355370
356371 it ( 'rejects empty content' , ( ) => {
@@ -363,26 +378,26 @@ describe('NIP-03 — OpenTimestamps', () => {
363378
364379 it ( 'rejects proofs whose digest does not match the event id' , ( ) => {
365380 const other = '0' . repeat ( 64 )
366- expect ( validateOtsProof ( validProof , other ) ) . to . match ( / d i g e s t d o e s n o t m a t c h / )
381+ expect ( validateOtsProof ( VALID_PROOF_BASE64 , other ) ) . to . match ( / d i g e s t d o e s n o t m a t c h / )
367382 } )
368383
369384 it ( 'rejects target ids that are not 32-byte hex' , ( ) => {
370- expect ( validateOtsProof ( validProof , 'not-an-id' ) ) . to . match ( / n o t a 3 2 - b y t e h e x / )
385+ expect ( validateOtsProof ( VALID_PROOF_BASE64 , 'not-an-id' ) ) . to . match ( / n o t a 3 2 - b y t e h e x / )
371386 } )
372387
373388 it ( 'rejects a non-string target event id' , ( ) => {
374- expect ( validateOtsProof ( validProof , null as unknown as string ) ) . to . match ( / n o t a 3 2 - b y t e h e x / )
389+ expect ( validateOtsProof ( VALID_PROOF_BASE64 , null as unknown as string ) ) . to . match ( / n o t a 3 2 - b y t e h e x / )
375390 } )
376391
377392 it ( 'rejects proofs without any bitcoin attestation' , ( ) => {
378- const onlyPending = buildOts ( DIGEST , [ pendingAttestation ( 'https://a.pool.opentimestamps.org' ) ] ) . toString ( 'base64' )
393+ const onlyPending = buildOts ( DIGEST , [ PENDING_ATTESTATION_DEFAULT ] ) . toString ( 'base64' )
379394 expect ( validateOtsProof ( onlyPending , EVENT_ID ) ) . to . match ( / b i t c o i n a t t e s t a t i o n / )
380395 } )
381396
382397 it ( 'rejects a proof digested with a non-sha256 hash op' , ( ) => {
383398 // Construct a manual RIPEMD160 file (20-byte digest) — this should fail
384399 // the sha256 requirement even though the parser would otherwise accept it.
385- const parts = [ MAGIC , writeVarUint ( 1 ) , Buffer . from ( [ 0x03 ] ) , Buffer . alloc ( 20 , 0xaa ) , bitcoinAttestation ( 1 ) ]
400+ const parts = [ MAGIC , writeVarUint ( 1 ) , Buffer . from ( [ 0x03 ] ) , Buffer . alloc ( 20 , 0xaa ) , BITCOIN_ATTESTATION_1 ]
386401 const ripemd = Buffer . concat ( parts ) . toString ( 'base64' )
387402 expect ( validateOtsProof ( ripemd , 'aa' . repeat ( 32 ) ) ) . to . match ( / s h a 2 5 6 f i l e h a s h o p / )
388403 } )
0 commit comments