这是代码:
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"fmt"
)
func main() {
msg := "Any random message"
curve := elliptic.P224()
key, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
fmt.Println(err)
}
r, s, err := ecdsa.Sign(rand.Reader, key, []byte(msg))
if err != nil {
fmt.Println(err)
}
// fmt.Println("r: ", r)
// fmt.Println("s: ", s)
publicKey := key.Public()
isVerified := ecdsa.Verify(publicKey.(*ecdsa.PublicKey), []byte(msg), r, s)
fmt.Println("isVerified: ", isVerified)
fmt.Println("key.PublicKey: ", key.PublicKey)
fmt.Println("key.D: ", key.D)
fmt.Println("key.Public() : ", publicKey)
fmt.Printf("Type of publicKey: %T\n", publicKey)//*ecdsa.PublicKey
}
为什么在ecdsa.Verify()
上调用publicKey
时需要类型声明?当我打印
publicKey
的类型时,它清楚地表明它是*ecdsa.PublicKey
类型,即相应的函数参数所需的类型,但相反,它被解释为crypto.PublicKey
类型。这是错误消息:
./main.go:25:28: cannot use publicKey (type crypto.PublicKey) as type *ecdsa.PublicKey in argument to ecdsa.Verify: need type assertion
最佳答案
正如您在文档中注意到的那样:
两种类型完全不同:
crypto.PublicKey
是一个接口(interface):它包含一个具体值和一个动态类型。在编译时,类型可以是任何东西,因此必须在运行时检查ecdsa.PublicKey
是接口(interface)的全部目的是接受任何实现接口(interface)的类型。在您的情况下,
publicKey
可以具有动态类型ecdsa.PublicKey
,rsa.PublicKey
甚至nil
。编译器允许它们全部。在调用需要特定类型的函数或方法时,编译器现在将需要所请求的实际类型。这可以使用type assertion或type switch完成。
在简单的示例中,您可能会发现它没有必要,但可以考虑在 key 生成和验证之间添加一些中介(例如允许使用不同类型的 key ),并且最终可能会使用不同的 key 基础类型(一种是
ecdsa.PublicKey
,另一种是rsa.PublicKey
) )。 crypto.PublicKey
接口(interface)允许轻松传递此 key ,但是在实际使用它时,必须检查动态类型。最后:用
*ecdsa.PublicKey
动词打印时看到%T
的原因是print calls reflect.TypeOf。对于docs,这是传入接口(interface)(或nil
)的动态类型。关于go - 在函数ecdsa.Verify上输入断言,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/63370048/