diff --git a/x/logic/interpreter/registry.go b/x/logic/interpreter/registry.go index e3e1bb06..6dfefb64 100644 --- a/x/logic/interpreter/registry.go +++ b/x/logic/interpreter/registry.go @@ -116,6 +116,7 @@ var Registry = map[string]RegistryEntry{ "bank_locked_balances/2": {predicate.BankLockedBalances, 1}, "did_components/2": {predicate.DIDComponents, 1}, "sha_hash/2": {predicate.SHAHash, 1}, + "hex_bytes/2": {predicate.HexBytes, 1}, } // RegistryNames is the list of the predicate names in the Registry. diff --git a/x/logic/predicate/crypto.go b/x/logic/predicate/crypto.go index ae6e0522..2a448c18 100644 --- a/x/logic/predicate/crypto.go +++ b/x/logic/predicate/crypto.go @@ -2,9 +2,11 @@ package predicate import ( "context" + "encoding/hex" "fmt" "github.com/ichiban/prolog/engine" + "github.com/okp4/okp4d/x/logic/util" "github.com/tendermint/tendermint/crypto" ) @@ -20,3 +22,45 @@ func SHAHash(vm *engine.VM, data, hash engine.Term, cont engine.Cont, env *engin } }) } + +func HexBytes(vm *engine.VM, hexa, bts engine.Term, cont engine.Cont, env *engine.Env) *engine.Promise { + return engine.Delay(func(ctx context.Context) *engine.Promise { + var result []byte + + switch h := env.Resolve(hexa).(type) { + case engine.Variable: + case engine.Atom: + src := []byte(h.String()) + result = make([]byte, hex.DecodedLen(len(src))) + _, err := hex.Decode(result, src) + if err != nil { + return engine.Error(fmt.Errorf("hex_bytes/2: failed decode hexadecimal %w", err)) + } + default: + return engine.Error(fmt.Errorf("hex_bytes/2: invalid hex type: %T, should be Atom or Variable", h)) + } + + switch b := env.Resolve(bts).(type) { + case engine.Variable: + if result == nil { + return engine.Error(fmt.Errorf("hex_bytes/2: nil hexadecimal conversion in input")) + } + return engine.Unify(vm, bts, BytesToList(result), cont, env) + case engine.Compound: + if b.Arity() != 2 || b.Functor().String() != "." { + return engine.Error(fmt.Errorf("hex_bytes/2: bytes should be a List, give %T", b)) + } + iter := engine.ListIterator{List: b, Env: env} + + src, err := ListToBytes(iter, env) + if err != nil { + return engine.Error(fmt.Errorf("hex_bytes/2: failed convert list into bytes: %w", err)) + } + dst := hex.EncodeToString(src) + return engine.Unify(vm, hexa, util.StringToTerm(dst), cont, env) + default: + return engine.Error(fmt.Errorf("hex_bytes/2: invalid hex type: %T, should be Variable or List", b)) + } + + }) +} diff --git a/x/logic/predicate/util.go b/x/logic/predicate/util.go index 4e29b985..eaab5591 100644 --- a/x/logic/predicate/util.go +++ b/x/logic/predicate/util.go @@ -68,10 +68,6 @@ func ListToBytes(terms engine.ListIterator, env *engine.Env) ([]byte, error) { term := env.Resolve(terms.Current()) switch t := term.(type) { case engine.Integer: - //b, ok := - //if !ok { - // return nil, fmt.Errorf("couldn't cast '%d' to byte", term) - //} bt = append(bt, byte(t)) default: return nil, fmt.Errorf("invalid term type in list %T, only integer allowed", term)