159 lines
3.4 KiB
Go
159 lines
3.4 KiB
Go
package opentimestamps
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
)
|
|
|
|
const maxResultLength = 4096
|
|
|
|
type (
|
|
unaryMsgOp func(message []byte) ([]byte, error)
|
|
binaryMsgOp func(message, argument []byte) ([]byte, error)
|
|
)
|
|
|
|
// msgAppend returns the concatenation of msg and arg
|
|
func msgAppend(msg, arg []byte) (res []byte, err error) {
|
|
res = append(res, msg...)
|
|
res = append(res, arg...)
|
|
return
|
|
}
|
|
|
|
// msgPrepend returns the concatenation of arg and msg
|
|
func msgPrepend(msg, arg []byte) (res []byte, err error) {
|
|
res = append(res, arg...)
|
|
res = append(res, msg...)
|
|
return
|
|
}
|
|
|
|
// msgReverse returns the reversed msg. Deprecated.
|
|
func msgReverse(msg []byte) ([]byte, error) {
|
|
if len(msg) == 0 {
|
|
return nil, fmt.Errorf("empty input invalid for msgReverse")
|
|
}
|
|
res := make([]byte, len(msg))
|
|
for i, b := range msg {
|
|
res[len(res)-i-1] = b
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func msgHexlify(msg []byte) ([]byte, error) {
|
|
if len(msg) == 0 {
|
|
return nil, fmt.Errorf("empty input invalid for msgHexlify")
|
|
}
|
|
return []byte(hex.EncodeToString(msg)), nil
|
|
}
|
|
|
|
type opCode interface {
|
|
match(byte) bool
|
|
decode(*deserializationContext) (opCode, error)
|
|
encode(*serializationContext) error
|
|
apply(message []byte) ([]byte, error)
|
|
}
|
|
|
|
type op struct {
|
|
tag byte
|
|
name string
|
|
}
|
|
|
|
func (o op) match(tag byte) bool {
|
|
return o.tag == tag
|
|
}
|
|
|
|
type unaryOp struct {
|
|
op
|
|
msgOp unaryMsgOp
|
|
}
|
|
|
|
func newUnaryOp(tag byte, name string, msgOp unaryMsgOp) *unaryOp {
|
|
return &unaryOp{op{tag: tag, name: name}, msgOp}
|
|
}
|
|
|
|
func (u *unaryOp) String() string {
|
|
return u.name
|
|
}
|
|
|
|
func (u *unaryOp) decode(ctx *deserializationContext) (opCode, error) {
|
|
ret := *u
|
|
return &ret, nil
|
|
}
|
|
|
|
func (u *unaryOp) encode(ctx *serializationContext) error {
|
|
return ctx.writeByte(u.tag)
|
|
}
|
|
|
|
func (u *unaryOp) apply(message []byte) ([]byte, error) {
|
|
return u.msgOp(message)
|
|
}
|
|
|
|
// Binary operations
|
|
// We decode an extra varbyte argument and use it in apply()
|
|
|
|
type binaryOp struct {
|
|
op
|
|
msgOp binaryMsgOp
|
|
argument []byte
|
|
}
|
|
|
|
func newBinaryOp(tag byte, name string, msgOp binaryMsgOp) *binaryOp {
|
|
return &binaryOp{
|
|
op: op{tag: tag, name: name},
|
|
msgOp: msgOp,
|
|
argument: nil,
|
|
}
|
|
}
|
|
|
|
func (b *binaryOp) decode(ctx *deserializationContext) (opCode, error) {
|
|
arg, err := ctx.readVarBytes(0, maxResultLength)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(arg) == 0 {
|
|
return nil, fmt.Errorf("empty argument invalid for binaryOp")
|
|
}
|
|
ret := *b
|
|
ret.argument = arg
|
|
return &ret, nil
|
|
}
|
|
|
|
func (b *binaryOp) encode(ctx *serializationContext) error {
|
|
if err := ctx.writeByte(b.tag); err != nil {
|
|
return err
|
|
}
|
|
return ctx.writeVarBytes(b.argument)
|
|
}
|
|
|
|
func (b *binaryOp) apply(message []byte) ([]byte, error) {
|
|
return b.msgOp(message, b.argument)
|
|
}
|
|
|
|
func (b *binaryOp) String() string {
|
|
return fmt.Sprintf("%s %x", b.name, b.argument)
|
|
}
|
|
|
|
func msgSHA256(msg []byte) ([]byte, error) {
|
|
res := sha256.Sum256(msg)
|
|
return res[:], nil
|
|
}
|
|
|
|
var (
|
|
opAppend = newBinaryOp(0xf0, "APPEND", msgAppend)
|
|
opPrepend = newBinaryOp(0xf1, "PREPEND", msgPrepend)
|
|
opReverse = newUnaryOp(0xf2, "REVERSE", msgReverse)
|
|
opHexlify = newUnaryOp(0xf3, "HEXLIFY", msgHexlify)
|
|
opSHA256 = newUnaryOp(0x08, "SHA256", msgSHA256)
|
|
)
|
|
|
|
var opCodes []opCode = []opCode{opAppend, opPrepend, opReverse, opHexlify, opSHA256}
|
|
|
|
func parseOp(ctx *deserializationContext, tag byte) (opCode, error) {
|
|
for _, op := range opCodes {
|
|
if op.match(tag) {
|
|
return op.decode(ctx)
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("could not decode tag %02x", tag)
|
|
}
|