Skip to content

Commit

Permalink
feat(logic): manage ecda secp256k1 key for secp_verify/4
Browse files Browse the repository at this point in the history
  • Loading branch information
bdeneux authored and ccamel committed Oct 27, 2023
1 parent 31e29d1 commit 268e493
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 35 deletions.
1 change: 1 addition & 0 deletions x/logic/interpreter/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ var registry = map[string]any{
"uri_encoded/3": predicate.URIEncoded,
"read_string/3": predicate.ReadString,
"eddsa_verify/4": predicate.ECDSAVerify,
"secp_verify/4": predicate.SecpVerify,
}

// RegistryNames is the list of the predicate names in the Registry.
Expand Down
78 changes: 43 additions & 35 deletions x/logic/predicate/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import (
"context"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"fmt"
"math/big"

cometcrypto "github.com/cometbft/cometbft/crypto"
"github.com/ichiban/prolog/engine"

"github.com/okp4/okp4d/x/logic/util"
)

Expand Down Expand Up @@ -139,6 +138,36 @@ func ECDSAVerify(vm *engine.VM, key, data, sig, options engine.Term, cont engine
})
}

func SecpVerify(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("secp_verify/4: decoding public key: %w", err))
}

msg, err := TermToBytes(data, env)
if err != nil {
return engine.Error(fmt.Errorf("secp_verify/4: decoding data: %w", err))
}

signature, err := TermToBytes(sig, env)
if err != nil {
return engine.Error(fmt.Errorf("secp_verify/4: decoding signature: %w", err))
}

// TODO: Create function hasDecoding option
r, err := verifySignature(Secp256r1, pubKey, msg, signature)
if err != nil {
return engine.Error(fmt.Errorf("secp_verify/4: failed verify signature: %w", err))
}

if !r {
return engine.Bool(false)
}
return cont(env)
})
}

func verifySignature(alg Alg, pubKey []byte, msg, sig []byte) (r bool, err error) {
defer func() {
if recoveredErr := recover(); recoveredErr != nil {
Expand All @@ -150,15 +179,17 @@ func verifySignature(alg Alg, pubKey []byte, msg, sig []byte) (r bool, err error
case Ed25519:
r = ed25519.Verify(pubKey, msg, sig)
case Secp256r1:
//pub, err := secp256r1BytesToPublicKey(pubKey)
//
//var pub secp256r1.PubKey
//pub = pubKey
//secp256r1.PubKey{Key: pubKey}
//if key, ok := pubKey.(); ok {
// return key.VerifySignature(msg, sig), nil
//}
err = fmt.Errorf("public key is not secp256r1 compatible")
block, _ := pem.Decode(pubKey)
if block == nil {
err = fmt.Errorf("failed decode PEM public key")
break
}
genericPublicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
break
}
pk := genericPublicKey.(*ecdsa.PublicKey)
r = ecdsa.VerifyASN1(pk, msg, sig)
case Secp256k1:
//if key, ok := pubKey.(secp256k1.PubKey); ok {
// return key.VerifySignature(msg, sig), nil
Expand All @@ -170,26 +201,3 @@ func verifySignature(alg Alg, pubKey []byte, msg, sig []byte) (r bool, err error

return r, err
}

func secp256r1BytesToPublicKey(pubKeyBytes []byte) (*ecdsa.PublicKey, error) {
curve := elliptic.P256()

// La longueur de la séquence de bytes doit être 2 * la longueur des points de la courbe elliptique + 1 (pour le byte de préfixe non compressé)
if len(pubKeyBytes) != 2*curve.Params().BitSize/8+1 {
return nil, fmt.Errorf("public key size is not good: %d expected, got %d", 2*curve.Params().BitSize/8+1, len(pubKeyBytes))
}

xBytes := pubKeyBytes[1 : curve.Params().BitSize/8+1]
yBytes := pubKeyBytes[curve.Params().BitSize/8+1:]

x := new(big.Int).SetBytes(xBytes)
y := new(big.Int).SetBytes(yBytes)

publicKey := &ecdsa.PublicKey{
Curve: curve,
X: x,
Y: y,
}

return publicKey, nil
}
44 changes: 44 additions & 0 deletions x/logic/predicate/crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,49 @@ ecdsa_verify(PubKey, Msg, Sig, _).`,
query: `verify.`,
wantSuccess: false,
},
{
// All good
program: `verify :-
hex_bytes('2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0d0a4d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414545386843612b527835565547393835506666565870433478446643660d0a6b75747a4c4b4d49586e6c383735734543525036654b4b79704c70514564564752526b3551396f687a64766b49392b583850756d666766356d673d3d0d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d', PubKey),
hex_bytes('e50c26e89f734b2ee12041ff27874c901891f74a0f0cf470333312a3034ce3be', Msg),
hex_bytes('30450220099e6f9dd218e0e304efa7a4224b0058a8e3aec73367ec239bee4ed8ed7d85db022100b504d3d0d2e879b04705c0e5a2b40b0521a5ab647ea207bd81134e1a4eb79e47', Sig),
secp_verify(PubKey, Msg, Sig, _).`,
query: `verify.`,
wantResult: []types.TermResults{{}},
wantSuccess: true,
},
{ // Invalid secp signature
program: `verify :-
hex_bytes('53167ac3fc4b720daa45b04fc73fe752578fa23a10048422d6904b7f4f7bba5a', PubKey),
hex_bytes('9b038f8ef6918cbb56040dfda401b56bb1ce79c472e7736e8677758c83367a9d', Msg),
hex_bytes('889bcfd331e8e43b5ebf430301dffb6ac9e2fce69f6227b43552fe3dc8cc1ee00c1cc53452a8712e9d5f80086dff8cf4999c1b93ed6c6e403c09334cb61ddd0b', Sig),
secp_verify(PubKey, Msg, Sig, _).`,
query: `verify.`,
wantSuccess: false,
wantError: fmt.Errorf("secp_verify/4: failed verify signature: failed decode PEM public key"),
},
{
// Wrong msg
program: `verify :-
hex_bytes('2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0d0a4d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414545386843612b527835565547393835506666565870433478446643660d0a6b75747a4c4b4d49586e6c383735734543525036654b4b79704c70514564564752526b3551396f687a64766b49392b583850756d666766356d673d3d0d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d', PubKey),
hex_bytes('e50c26e89f734b2ee12041ff27874c901891f74a0f0cf470333312a3034ce3bf', Msg),
hex_bytes('30450220099e6f9dd218e0e304efa7a4224b0058a8e3aec73367ec239bee4ed8ed7d85db022100b504d3d0d2e879b04705c0e5a2b40b0521a5ab647ea207bd81134e1a4eb79e47', Sig),
secp_verify(PubKey, Msg, Sig, _).`,
query: `verify.`,
wantResult: []types.TermResults{{}},
wantSuccess: false,
},
{
// Wrong signature
program: `verify :-
hex_bytes('2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0d0a4d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414545386843612b527835565547393835506666565870433478446643660d0a6b75747a4c4b4d49586e6c383735734543525036654b4b79704c70514564564752526b3551396f687a64766b49392b583850756d666766356d673d3d0d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d', PubKey),
hex_bytes('e50c26e89f734b2ee12041ff27874c901891f74a0f0cf470333312a3034ce3be', Msg),
hex_bytes('30450220099e6f9dd218e0e304efa7a4224b0058a8e3aec73367ec239bee4ed8ed7d85db022100b504d3d0d2e879b04705c0e5a2b40b0521a5ab647ea207bd81134e1a4eb79e48', Sig),
secp_verify(PubKey, Msg, Sig, _).`,
query: `verify.`,
wantResult: []types.TermResults{{}},
wantSuccess: false,
},
}
for nc, tc := range cases {
Convey(fmt.Sprintf("Given the query #%d: %s", nc, tc.query), func() {
Expand All @@ -231,6 +274,7 @@ ecdsa_verify(PubKey, Msg, Sig, _).`,
interpreter := testutil.NewLightInterpreterMust(ctx)
interpreter.Register2(engine.NewAtom("hex_bytes"), HexBytes)
interpreter.Register4(engine.NewAtom("ecdsa_verify"), ECDSAVerify)
interpreter.Register4(engine.NewAtom("secp_verify"), SecpVerify)

err := interpreter.Compile(ctx, tc.program)
So(err, ShouldBeNil)
Expand Down

0 comments on commit 268e493

Please sign in to comment.