【问题标题】:Interoperability between javascript's elliptic library and golang's ecdsa libraryjavascript的椭圆库和golang的ecdsa库的互操作性
【发布时间】:2020-09-20 05:51:19
【问题描述】:

我在使用 golang 的 ecdsa 库验证椭圆 javascript 库生成的签名时遇到困难。使用的椭圆曲线是 secp256k1。

这里有一些代码sn-ps:

Typescript 实用函数:

import * as bigInt from 'big-integer';
declare const require: any;
var EC = require('elliptic').ec;
var ec = new EC('secp256k1');
const SHA256 = require("crypto-js/sha256");


const generatePrivateKey = function(): string {
    return ec.genKeyPair().getPrivate().toString();
}

const generatePublicKey = function(privateKey: string): PublicKey {
    const publicKey: any = ec.keyFromPrivate(privateKey).getPublic();
    return new PublicKey(
        publicKey.getX().toString("hex"),
        publicKey.getY().toString("hex")
    );
}

const signMessage = function(message: string, privateKey: string): Signature {
    message = SHA256(message).toString();
    const key = ec.keyFromPrivate(privateKey);
    const signature: Signature = JSON.parse(JSON.stringify(key.sign(message)));
    return new Signature(signature.r, signature.s, signature.recoveryParam);
}

const verifyMessage = function(message: string, publicKey: PublicKey, signature: Signature): boolean {
    message = SHA256(message).toString();
    const key = ec.keyFromPublic(publicKey, 'hex');
    return key.verify(message, signature);
}

class PublicKey {
    constructor(
        public x: string,
        public y: string
    ) { }
}

class Signature {
    constructor(
        public r: string,
        public s: string,
        public recoveryParam: number
    ) { }
}

使用上述函数生成的示例签名:

// Private Key
const privateKey = "87447468790127269743127941512029311682561810964950681691418579250915022213638"

// Public Key
const publicKey = {
  x: 'fe0f1982436d08bfc2a603d85738bc874cbc4d2108e63eca0264afd8e62244df',
  y: '199b6155f2532aa5d6404c32ea5fb7de1c9af741b99d75dcb73285bfd8525176'
}

// Sample message
const message = "hello world"

// Generated Signature
const signature = {
  r: 'be4022f929aa1aef40e563a0e30e1b23b9ca5a73d510cf9d95a2a51db4f52965',
  s: 'c27b747099192bda25985fdd5dd588de44c40b15aa038aa65399aa5e9e5ec7b',
  recoveryParam: 1
}

用于验证签名的Go代码:

xVal := new(big.Int)
xVal.SetString("fe0f1982436d08bfc2a603d85738bc874cbc4d2108e63eca0264afd8e62244df", 16)
yVal := new(big.Int)
yVal.SetString("199b6155f2532aa5d6404c32ea5fb7de1c9af741b99d75dcb73285bfd8525176", 16)

rVal := new(big.Int)
rVal.SetString("be4022f929aa1aef40e563a0e30e1b23b9ca5a73d510cf9d95a2a51db4f52965", 16)
sVal := new(big.Int)
sVal.SetString("c27b747099192bda25985fdd5dd588de44c40b15aa038aa65399aa5e9e5ec7b", 16)


hash := fmt.Sprintf(
    "%x",
    sha256.Sum256([]byte("hello world")),
)

pubKey := ecdsa.PublicKey{
    Curve: secp256k1.S256(),
    X:     xVal,
    Y:     yVal,
}

fmt.Printf("SIG VERIFICATION: %v", ecdsa.Verify(&pubKey, []byte(hash), rVal, sVal))

输出是:

SIG VERIFICATION: false

输出应该为真。如果对更多细节有任何疑问,请通知我。

Javascript Elliptic Library

Golang edcsa library

【问题讨论】:

  • 密钥对是使用椭圆js库生成的。根据库,密钥对是有效的
  • 尝试使用hex.DecodeString(hash)而不是[]byte(...;来解码你的十六进制字符串
  • @Topaco 源代码已更新。有关任何进一步的细节,您可以参考库的源代码github.com/indutny/elliptic
  • @mh-cbon 你是个天才,问题解决了。此示例对于使用 Go 后端和移动或 Web 前端的个人来说非常方便。谢谢一百万。
  • 注意到了。 @mh-cbon 反面有什么想法吗?它并不像看起来那么简单

标签: javascript typescript go cryptography elliptic-curve


【解决方案1】:

解决方案是使用 DecodeString 函数对消息散列进行散列。以下是解决方案的更新代码:

xVal := new(big.Int)
xVal.SetString("fe0f1982436d08bfc2a603d85738bc874cbc4d2108e63eca0264afd8e62244df", 16)
yVal := new(big.Int)
yVal.SetString("199b6155f2532aa5d6404c32ea5fb7de1c9af741b99d75dcb73285bfd8525176", 16)

rVal := new(big.Int)
rVal.SetString("be4022f929aa1aef40e563a0e30e1b23b9ca5a73d510cf9d95a2a51db4f52965", 16)
sVal := new(big.Int)
sVal.SetString("c27b747099192bda25985fdd5dd588de44c40b15aa038aa65399aa5e9e5ec7b", 16)

msgHash := fmt.Sprintf(
    "%x",
    sha256.Sum256([]byte("hello world")),
)
    
pubKey := ecdsa.PublicKey{
    Curve: secp256k1.S256(),
    X:     xVal,
    Y:     yVal,
}

hash, hashDecodeError := hex.DecodeString(msgHash)

if hashDecodeError != nil {
    log.Println(hashDecodeError)
    panic("internal server error")
}

fmt.Printf("SIG VERIFICATION: %v", ecdsa.Verify(&pubKey, hash, rVal, sVal))

使用上述代码的验证结果为真。

感谢用户 mh-cbon 的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-11
    • 1970-01-01
    • 2021-07-31
    • 1970-01-01
    • 2010-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多