Skip to content

Commit

Permalink
Merge pull request #769 from fiatjaf/opentimestamps
Browse files Browse the repository at this point in the history
add OpenTimestamps file parser
  • Loading branch information
wader authored Sep 26, 2023
2 parents 832b184 + 976a756 commit a67427b
Show file tree
Hide file tree
Showing 16 changed files with 2,657 additions and 931 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ mpeg_ts,
[msgpack](doc/formats.md#msgpack),
ogg,
ogg_page,
[opentimestamps](doc/formats.md#opentimestamps),
opus_packet,
[pcap](doc/formats.md#pcap),
pcapng,
Expand Down
30 changes: 29 additions & 1 deletion doc/formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
|[`msgpack`](#msgpack) |MessagePack |<sub></sub>|
|`ogg` |OGG&nbsp;file |<sub>`ogg_page` `vorbis_packet` `opus_packet` `flac_metadatablock` `flac_frame`</sub>|
|`ogg_page` |OGG&nbsp;page |<sub></sub>|
|[`opentimestamps`](#opentimestamps) |OpenTimestamps&nbsp;file |<sub></sub>|
|`opus_packet` |Opus&nbsp;packet |<sub>`vorbis_comment`</sub>|
|[`pcap`](#pcap) |PCAP&nbsp;packet&nbsp;capture |<sub>`link_frame` `tcp_stream` `ipv4_packet`</sub>|
|`pcapng` |PCAPNG&nbsp;packet&nbsp;capture |<sub>`link_frame` `tcp_stream` `ipv4_packet`</sub>|
Expand Down Expand Up @@ -130,7 +131,7 @@
|`ip_packet` |Group |<sub>`icmp` `icmpv6` `tcp_segment` `udp_datagram`</sub>|
|`link_frame` |Group |<sub>`bsd_loopback_frame` `ether8023_frame` `ipv4_packet` `ipv6_packet` `sll2_packet` `sll_packet`</sub>|
|`mp3_frame_tags` |Group |<sub>`mp3_frame_vbri` `mp3_frame_xing`</sub>|
|`probe` |Group |<sub>`adts` `aiff` `apple_bookmark` `ar` `avi` `avro_ocf` `bitcoin_blkdat` `bplist` `bzip2` `caff` `elf` `flac` `gif` `gzip` `html` `jpeg` `json` `jsonl` `luajit` `macho` `macho_fat` `matroska` `moc3` `mp3` `mp4` `mpeg_ts` `ogg` `pcap` `pcapng` `png` `tar` `tiff` `toml` `tzif` `wasm` `wav` `webp` `xml` `yaml` `zip`</sub>|
|`probe` |Group |<sub>`adts` `aiff` `apple_bookmark` `ar` `avi` `avro_ocf` `bitcoin_blkdat` `bplist` `bzip2` `caff` `elf` `flac` `gif` `gzip` `html` `jpeg` `json` `jsonl` `luajit` `macho` `macho_fat` `matroska` `moc3` `mp3` `mp4` `mpeg_ts` `ogg` `opentimestamps` `pcap` `pcapng` `png` `tar` `tiff` `toml` `tzif` `wasm` `wav` `webp` `xml` `yaml` `zip`</sub>|
|`tcp_stream` |Group |<sub>`dns_tcp` `rtmp` `tls`</sub>|
|`udp_payload` |Group |<sub>`dns`</sub>|

Expand Down Expand Up @@ -856,6 +857,33 @@ $ fq -d msgpack torepr file.msgpack
### References
- https://github.com/msgpack/msgpack/blob/master/spec.md

## opentimestamps

### View a full OpenTimestamps file

```
$ fq dd file.ots
```

### List the names of the Calendar servers used

```
$ fq '.operations | map(select(.attestation_type == "calendar") | .url)' file.ots
```

### Check if there are Bitcoin attestations present

```
$ fq '.operations | map(select(.attestation_type == "bitcoin")) | length > 0' file.ots
```

### Authors
- fiatjaf, https://fiatjaf.com

### References
- https://opentimestamps.org/
- https://github.com/opentimestamps/python-opentimestamps

## pcap

### Build object with number of (reassembled) TCP bytes sent to/from client IP
Expand Down
1,872 changes: 942 additions & 930 deletions doc/formats.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions format/all/all.fqtest
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ $ fq -n _registry.groups.probe
"moc3",
"mp4",
"ogg",
"opentimestamps",
"pcap",
"pcapng",
"png",
Expand Down Expand Up @@ -130,6 +131,7 @@ mpeg_ts MPEG Transport Stream
msgpack MessagePack
ogg OGG file
ogg_page OGG page
opentimestamps OpenTimestamps file
opus_packet Opus packet
pcap PCAP packet capture
pcapng PCAPNG packet capture
Expand Down
1 change: 1 addition & 0 deletions format/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (
_ "github.com/wader/fq/format/mpeg"
_ "github.com/wader/fq/format/msgpack"
_ "github.com/wader/fq/format/ogg"
_ "github.com/wader/fq/format/opentimestamps"
_ "github.com/wader/fq/format/opus"
_ "github.com/wader/fq/format/pcap"
_ "github.com/wader/fq/format/png"
Expand Down
1 change: 1 addition & 0 deletions format/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ var (
Bitcoin_Block = &decode.Group{Name: "bitcoin_block"}
Bitcoin_Script = &decode.Group{Name: "bitcoin_script"}
Bitcoin_Transaction = &decode.Group{Name: "bitcoin_transaction"}
Opentimestamps = &decode.Group{Name: "opentimestamps"}
Bplist = &decode.Group{Name: "bplist"}
BSD_Loopback_Frame = &decode.Group{Name: "bsd_loopback_frame"}
BSON = &decode.Group{Name: "bson"}
Expand Down
138 changes: 138 additions & 0 deletions format/opentimestamps/opentimestamps.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package opentimestamps

// https://opentimestamps.org/

import (
"embed"

"github.com/wader/fq/format"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/interp"
"github.com/wader/fq/pkg/scalar"
"golang.org/x/exp/slices"
)

//go:embed opentimestamps.md
var otsFS embed.FS

func init() {
interp.RegisterFormat(
format.Opentimestamps,
&decode.Format{
Description: "OpenTimestamps file",
DecodeFn: decodeOTSFile,
Groups: []*decode.Group{format.Probe},
})
interp.RegisterFS(otsFS)
}

const (
continuationByte = 0xff
attestationTag = 0x00
appendTag = 0xf0
prependTag = 0xf1
reverseTag = 0xf2
hexlifyTag = 0xf3
sha1Tag = 0x02
ripemd160Tag = 0x03
sha256Tag = 0x08
keccak256Tag = 0x67
)

var (
headerMagic = []byte{0x00, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x00, 0x00, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x00, 0xbf, 0x89, 0xe2, 0xe8, 0x84, 0xe8, 0x92, 0x94}
calendarMagic uint64 = 0x83_df_e3_0d_2e_f9_0c_8e
bitcoinMagic uint64 = 0x05_88_96_0d_73_d7_19_01

binaryTags = []byte{appendTag, prependTag}
)

var attestationMapper = scalar.UintMapSymStr{
calendarMagic: "calendar",
bitcoinMagic: "bitcoin",
}

var tagMapper = scalar.UintMapSymStr{
continuationByte: "continuation_byte",
attestationTag: "attestation",
appendTag: "append",
prependTag: "prepend",
reverseTag: "reverse",
hexlifyTag: "hexlify",
sha1Tag: "sha1",
ripemd160Tag: "ripemd160",
sha256Tag: "sha256",
keccak256Tag: "keccak256",
}

var digestSizes = map[byte]int64{
sha1Tag: 20,
ripemd160Tag: 20,
sha256Tag: 32,
keccak256Tag: 32,
}

func decodeOTSFile(d *decode.D) any {
d.Endian = decode.BigEndian

d.FieldRawLen("magic_bytes", int64(8*len(headerMagic)), d.AssertBitBuf(headerMagic))
d.FieldUintFn("version", decodeVarInt)

tag := d.FieldU8("digest_hash_algorithm", tagMapper)
digestSize, ok := digestSizes[byte(tag)]
if !ok {
name := tagMapper[tag]
d.Fatalf("hash algorithm not supported, got %x: '%s'", tag, name)
return nil
}
d.FieldRawLen("digest", 8*digestSize, scalar.RawHex)

d.FieldArray("operations", func(d *decode.D) {
for d.NotEnd() {
d.FieldStruct("operation", func(d *decode.D) {
tag := d.FieldU8("tag", tagMapper)
if tag == attestationTag {
val := d.FieldU64BE("attestation_type", attestationMapper)
n := d.FieldUintFn("attestation_varbytes_size", decodeVarInt)
switch val {
case bitcoinMagic:
d.FieldUintFn("block", decodeVarInt)
case calendarMagic:
nurl := d.FieldUintFn("url_size", decodeVarInt)
d.FieldUTF8("url", int(nurl))
default:
d.FieldRawLen("unknown_data", int64(n*8))
}
} else {
if _, ok := tagMapper[tag]; ok {
// read var bytes if argument
if slices.Contains(binaryTags, byte(tag)) {
n := d.FieldUintFn("argument_size", decodeVarInt)
d.FieldRawLen("argument", int64(8*n), scalar.RawHex)
}
} else {
d.Fatalf("unknown operation tag %x", tag)
}
}
})
}
})

return nil
}

func decodeVarInt(d *decode.D) uint64 {
var value uint64 = 0
var shift uint64 = 0

for {
b := d.U8()
value |= (b & 0b01111111) << shift
shift += 7
if b&0b10000000 == 0 {
break
}
}

return value
}
24 changes: 24 additions & 0 deletions format/opentimestamps/opentimestamps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
### View a full OpenTimestamps file

```
$ fq dd file.ots
```

### List the names of the Calendar servers used

```
$ fq '.operations | map(select(.attestation_type == "calendar") | .url)' file.ots
```

### Check if there are Bitcoin attestations present

```
$ fq '.operations | map(select(.attestation_type == "bitcoin")) | length > 0' file.ots
```

### Authors
- fiatjaf, https://fiatjaf.com

### References
- https://opentimestamps.org/
- https://github.com/opentimestamps/python-opentimestamps
Loading

0 comments on commit a67427b

Please sign in to comment.