const bigInt = require('big-integer') // Consts for secp256k1 curve. Adjust accordingly // https://en.bitcoin.it/wiki/Secp256k1 const prime = new bigInt('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16), // 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 pIdent = new bigInt('3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c', 16) // prime.add(1).divide(4); console.log('pIdent=', pIdent.toString(), ' = ', pIdent.toString(16)) /** * Point decompress secp256k1 curve * @param {string} Compressed representation in hex string * @return {string} Uncompressed representation in hex string */ function ECPointDecompress (comp) { var signY = new Number(comp[1]) - 2 var x = new bigInt(comp.substring(2), 16) // y mod p = +-(x^3 + 7)^((p+1)/4) mod p console.log('ECP x=', x.toString(), ' = ', x.toString(16)) var y = x.modPow(3, prime).add(7).mod(prime).modPow(pIdent, prime) // If the parity doesn't match it's the *other* root console.log('ECP y=', y.toString(), ' = ', y.toString(16)) if (y.mod(2).toJSNumber() !== signY) { // y = prime - y y = prime.subtract(y) } console.log('ECP y=', y.toString(), ' = ', y.toString(16)) return '04' + x.toString(16).padStart(64, '0') + y.toString(16).padStart(64, '0') } let pubkey1 = ECPointDecompress('035d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b2') console.log(pubkey1) // "045d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b24a323dd24b19c55f0a060ccd4bce314323bd7e804f3dfa8a77f14e3ab1cc4749" correct = '045d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b2356d086fb7a78f3ce3359a4caee6dd4fcf0c19a961b1c36b5b442d031d219d75' BigNumber = require('bignumber.js') function uncompressPubkey (comp) { // Consts for P256 curve. Adjust accordingly const prime = new BigNumber('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16).integerValue(), pIdent = prime.plus(1).idiv(4).integerValue() console.log('pIdent=', pIdent.toString(), ' = ', pIdent.toString(16)) var signY = new Number(comp[1]) - 2 var x = new BigNumber(comp.substring(2), 16).integerValue() console.log('x=', x.toString(), ' = ', x.toString(16)) // y^2 = x^3 - 3x + b var y = x.pow(3).mod(prime).plus(7).mod(prime).pow(pIdent).mod(prime).integerValue() console.log('y=', y.toString(), ' = ', y.toString(16)) // If the parity doesn't match it's the *other* root if (y.mod(2).integerValue().toNumber() !== signY) { // y = prime - y y = prime.minus(y).integerValue() } console.log('yy=', y.toString(), ' = ', y.toString(16)) return '04' + x.toString(16).padStart(64, '0') + y.toString(16).padStart(64, '0') } let pubkey2 = uncompressPubkey('035d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b2') console.log(pubkey2) /////////////////////////////////////// const tic = require('./index') const crypto = require('crypto') const keyutil = require('js-crypto-key-utils') // https://github.com/junkurihara/jscu/tree/master/packages/js-crypto-key-utils // https://github.com/arvati/crypto-keys // nodejs cipher/decipher 用同一个密码,在stream上操作。 let w = '驳 惊 而 煤 靠 客 示 待 诉 屈 屏 未' // tic.randomize_secword({lang:'chinese'}) console.log('secword = ', w) let acc = tic.secword_to_account({ secword: w, coin: 'ETH' }) console.log('account = ', acc) let add = tic.secword_to_address({ secword: w, coin: 'ETH' }) console.log('address = ', add) /////////////////////// keyutil let seckeyObject = new keyutil.Key('oct', Buffer.from(acc.prikey, 'hex'), { namedCurve: 'P-256K' }) // {P-256 : secp256r1, P-384 : secp384r1, P-521 : secp521r1, P-256K : secp256k1} let seckeyObject2 = new keyutil.Key('oct', tic.hex_to_buf(acc.prikey, 'hex'), { namedCurve: 'P-256K' }) let seckeyPEM seckeyObject.export('pem').then((data) => (seckeyPEM = data)) let seckeyDER seckeyObject2.export('der').then((data) => (seckeyDER = data)) var signerKU = crypto.createSign('sha256') signerKU.write('毛主席万岁') signerKU.end() var signatureKU = signerKU.sign(seckeyPEM) // specify format in [pem,der] and type in [pkcs1, pkcs8, sec1] console.log('signature = ', signatureKU.toString('hex')) console.log('length = ', signatureKU.toString('hex').length) var signerKUDER = crypto.createSign('sha256') signerKUDER.write('毛主席万岁') signerKUDER.end() var signatureKUDER = signerKUDER.sign({ key: seckeyDER, format: 'der', type: 'pkcs8' }) // specify format in [pem,der] and type in [pkcs1, pkcs8, sec1] console.log('signature DER = ', signatureKUDER.toString('hex')) console.log('length DER = ', signatureKUDER.toString('hex').length) let pubkeyObject = new keyutil.Key('oct', Buffer.from(acc.pubkey, 'hex'), { namedCurve: 'P-256K' }) let pubkeyPEM pubkeyObject.export('der').then((data) => (pubkeyPEM = data)) var verifyKU = crypto.createVerify('sha256') verifyKU.write('毛主席万岁') verifyKU.end() var verified = verifyKU.verify(pubkeyPEM, signatureKU) // specify format in [pem,der] and type in [pkcs1,spki] console.log('verified = ', verified) // 可以验证通过,但是用的privatekey,没有成功使用publickey。 crypto.createCipheriv('aes-256-cfb', Buffer.from(acc.prikey, 'hex'), Buffer.alloc(16)) ////////////////////// crypto + PEM toPEM = function (kp) { let pubkey = crypto.createECDH('secp256k1').setPrivateKey(kp.prikey, 'hex').getPublicKey('hex', 'compressed') console.log('ECDH created publickey = ', pubkey) let mykey = '308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420' + kp.prikey + 'a144034200' + pubkey console.log(mykey) let privKey = '-----BEGIN PRIVATE KEY-----\n' + Buffer.from(mykey, 'hex').toString('base64') + '\n-----END PRIVATE KEY-----' // pubKey2 = crypto.createPublicKey(privKey); //也可恢复出公钥。测试不成功。 return privKey } let privKeyPEM = toPEM(acc) const signerPEM = crypto.createSign('sha256') signerPEM.write('毛主席万岁') signerPEM.end() let signaturePEM = signerPEM.sign(privKeyPEM, 'hex') // 失败,无论对压缩或非压缩公钥 console.log('signaturePEM = ', signaturePEM) let pemKP = toPEM(acc) console.log('pemKP = ', pemKP) //////////////////// crypto, DER // https://stackoverflow.com/questions/58350484/why-nodejs-crypto-sign-function-only-accept-privatekey-pem-format // https://www.shangyang.me/2017/05/24/encrypt-rsa-keyformat/ var buf1 = Buffer.from('308141020100301306072a8648ce3d020106082a8648ce3d030107042730250201010420', 'hex') // specific byte-sequence for curve prime256v1 var buf2 = Buffer.from(acc.prikey, 'hex') // raw private key (32 bytes) var privateKeyPkcs8Der = Buffer.concat([buf1, buf2], buf1.length + buf2.length) var sign = crypto.createSign('sha256') sign.write('毛主席万岁') sign.end() var signature = sign.sign({ key: privateKeyPkcs8Der, format: 'der', type: 'pkcs8' }) // specify format in [pem,der] and type in [pkcs1, pkcs8, sec1] console.log('signature = ', signature.toString('hex')) console.log('length = ', signature.toString('hex').length) var buf3 = Buffer.from('3059301306072a8648ce3d020106082a8648ce3d030107034200', 'hex') // specific byte-sequence for curve prime256v1 var buf4 = Buffer.from(acc.pubkey, 'hex') // raw public key (uncompressed, 65 bytes, startting with 04) // 这个key无法sign。reason: 'too long' //var publicKeyX509Der = Buffer.concat([buf3, buf4], buf3.length + buf4.length); //var publicKey = crypto.createPublicKey({key:publicKeyX509Der, format:'der', type:'spki'}) var publicKey = crypto.createPublicKey({ key: privateKeyPkcs8Der, type: 'pkcs8', format: 'der' }) var publicKeyX509Der = publicKey.export({ type: 'spki', format: 'der' }) var verify = crypto.createVerify('sha256') verify.write('毛主席万岁') verify.end() var verified = verify.verify({ key: publicKeyX509Der, format: 'der', type: 'spki' }, signature) // specify format in [pem,der] and type in [pkcs1,spki] console.log('verified = ', verified) // 可以验证通过,但是用的privatekey,没有成功使用publickey。 /////////////////////// elliptic var EC = require('elliptic').ec // Create and initialize EC context // (better do it once and reuse it) var ec = new EC('secp256k1') // Generate keys //var key = ec.genKeyPair(); var key = ec.keyFromPrivate(acc.prikey) // 注意,不需要 'hex' 参数 // Sign the message's hash (input must be an array, or a hex-string) var msgHash = tic.hash('毛主席万岁') var msgHashBad = tic.hash('毛主席万岁 ') var signature2 = key.sign(msgHash) // Export DER encoded signature in Array var derSign = signature2.toDER() // 无法直接导出成 hex。可以 console.log('signature by elliptic = ', Buffer.from(derSign).toString('hex')) // 或者重新创建使用 pubkey,也能成功 // ec.keyFromPublic(acc.pubkey, 'hex').verify(msgHash, signature2) console.log(key.verify(msgHash, signature2)) console.log(key.verify(msgHashBad, signature2)) ////////////////// /* createCipher/Decipher: 使用 pwd, 对称加解密。已放弃。 createCipheriv/Deciperiv: 使用 key, 对称加解密。 private/publicEncrypt/Decrypt: 非对称加解密。 crypto.privateEncrypt(crypto.generateKeyPairSync('rsa', {modulusLength:2048}).privateKey, Buffer.from('锦瑟无端五十弦')) 以上是唯一测出来可用的privatekey,不能用 'ec', {namedCurve:'secp256k1'}, 也不能用crypto.createPrivateKey(pem格式的字符串)。 */