From 2a19e9160871b7a631b53f096f84aecc6c80aa8a Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Fri, 6 Oct 2023 11:04:07 +0200 Subject: [PATCH] feat(logic): reigster eddsa_verify/4 predicate --- x/logic/interpreter/registry.go | 1 + x/logic/predicate/crypto.go | 29 ++++++++++++++++++++++++++++- x/logic/predicate/util.go | 14 ++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/x/logic/interpreter/registry.go b/x/logic/interpreter/registry.go index 63833c2d..fe5ba7f1 100644 --- a/x/logic/interpreter/registry.go +++ b/x/logic/interpreter/registry.go @@ -116,6 +116,7 @@ var registry = map[string]any{ "json_prolog/2": predicate.JSONProlog, "uri_encoded/3": predicate.URIEncoded, "read_string/3": predicate.ReadString, + "eddsa_verify/4": predicate.EDDSAVerify, } // 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 7359cc86..bd004719 100644 --- a/x/logic/predicate/crypto.go +++ b/x/logic/predicate/crypto.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "fmt" + cometcrypto "github.com/cometbft/cometbft/crypto" "github.com/cometbft/cometbft/crypto/secp256k1" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1" "github.com/ichiban/prolog/engine" @@ -37,7 +38,7 @@ func SHAHash(vm *engine.VM, data, hash engine.Term, cont engine.Cont, env *engin var result []byte switch d := env.Resolve(data).(type) { case engine.Atom: - result = crypto.Sha256([]byte(d.String())) + result = cometcrypto.Sha256([]byte(d.String())) return engine.Unify(vm, hash, BytesToList(result), cont, env) default: return engine.Error(fmt.Errorf("sha_hash/2: invalid data type: %T, should be Atom", d)) @@ -108,6 +109,32 @@ const ( Ed25519 Alg = "ed25519" ) +func EDDSAVerify(vm *engine.VM, key, data, sig, options engine.Term, cont engine.Cont, env *engine.Env) *engine.Promise { + return engine.Delay(func(ctx context.Context) *engine.Promise { + pubKey, err := TermToBytes(key, env) + if err != nil { + return engine.Error(fmt.Errorf("eddsa_verify/4: decoding public key: %w", err)) + } + + msg, err := TermToBytes(data, env) + if err != nil { + return engine.Error(fmt.Errorf("eddsa_verify/4: decoding data: %w", err)) + } + + signature, err := TermToBytes(sig, env) + if err != nil { + return engine.Error(fmt.Errorf("eddsa_verify/4: decoding signature: %w", err)) + } + + // TODO: Create function hasDecoding option + r, err := verifySignature(Ed25519, pubKey, msg, signature) + if err != nil { + return engine.Error(fmt.Errorf("eddsa_verify/4: failed verify signature: %w", err)) + } + return engine.Bool(r) + }) +} + func verifySignature(alg Alg, pubKey crypto.PublicKey, msg, sig []byte) (bool, error) { switch alg { case Ed25519: diff --git a/x/logic/predicate/util.go b/x/logic/predicate/util.go index 4718f3ee..009483cb 100644 --- a/x/logic/predicate/util.go +++ b/x/logic/predicate/util.go @@ -64,6 +64,20 @@ func BytesToList(bt []byte) engine.Term { return engine.List(terms...) } +func TermToBytes(term engine.Term, env *engine.Env) ([]byte, error) { + switch b := env.Resolve(term).(type) { + case engine.Compound: + if b.Arity() != 2 || b.Functor().String() != "." { + return nil, fmt.Errorf("term should be a List, give %T", b) + } + iter := engine.ListIterator{List: b, Env: env} + + return ListToBytes(iter, env) + default: + return nil, fmt.Errorf("invalid term type: %T, should be Atom or List", term) + } +} + func ListToBytes(terms engine.ListIterator, env *engine.Env) ([]byte, error) { bt := make([]byte, 0) for terms.Next() {