123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- 'use strict';
- var hash = require('hash.js');
- var curves = require('../curves');
- var utils = require('../utils');
- var assert = utils.assert;
- var parseBytes = utils.parseBytes;
- var KeyPair = require('./key');
- var Signature = require('./signature');
- function EDDSA(curve) {
- assert(curve === 'ed25519', 'only tested with ed25519 so far');
- if (!(this instanceof EDDSA))
- return new EDDSA(curve);
- curve = curves[curve].curve;
- this.curve = curve;
- this.g = curve.g;
- this.g.precompute(curve.n.bitLength() + 1);
- this.pointClass = curve.point().constructor;
- this.encodingLength = Math.ceil(curve.n.bitLength() / 8);
- this.hash = hash.sha512;
- }
- module.exports = EDDSA;
- /**
- * @param {Array|String} message - message bytes
- * @param {Array|String|KeyPair} secret - secret bytes or a keypair
- * @returns {Signature} - signature
- */
- EDDSA.prototype.sign = function sign(message, secret) {
- message = parseBytes(message);
- var key = this.keyFromSecret(secret);
- var r = this.hashInt(key.messagePrefix(), message);
- var R = this.g.mul(r);
- var Rencoded = this.encodePoint(R);
- var s_ = this.hashInt(Rencoded, key.pubBytes(), message)
- .mul(key.priv());
- var S = r.add(s_).umod(this.curve.n);
- return this.makeSignature({ R: R, S: S, Rencoded: Rencoded });
- };
- /**
- * @param {Array} message - message bytes
- * @param {Array|String|Signature} sig - sig bytes
- * @param {Array|String|Point|KeyPair} pub - public key
- * @returns {Boolean} - true if public key matches sig of message
- */
- EDDSA.prototype.verify = function verify(message, sig, pub) {
- message = parseBytes(message);
- sig = this.makeSignature(sig);
- if (sig.S().gte(sig.eddsa.curve.n) || sig.S().isNeg()) {
- return false;
- }
- var key = this.keyFromPublic(pub);
- var h = this.hashInt(sig.Rencoded(), key.pubBytes(), message);
- var SG = this.g.mul(sig.S());
- var RplusAh = sig.R().add(key.pub().mul(h));
- return RplusAh.eq(SG);
- };
- EDDSA.prototype.hashInt = function hashInt() {
- var hash = this.hash();
- for (var i = 0; i < arguments.length; i++)
- hash.update(arguments[i]);
- return utils.intFromLE(hash.digest()).umod(this.curve.n);
- };
- EDDSA.prototype.keyFromPublic = function keyFromPublic(pub) {
- return KeyPair.fromPublic(this, pub);
- };
- EDDSA.prototype.keyFromSecret = function keyFromSecret(secret) {
- return KeyPair.fromSecret(this, secret);
- };
- EDDSA.prototype.makeSignature = function makeSignature(sig) {
- if (sig instanceof Signature)
- return sig;
- return new Signature(this, sig);
- };
- /**
- * * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03#section-5.2
- *
- * EDDSA defines methods for encoding and decoding points and integers. These are
- * helper convenience methods, that pass along to utility functions implied
- * parameters.
- *
- */
- EDDSA.prototype.encodePoint = function encodePoint(point) {
- var enc = point.getY().toArray('le', this.encodingLength);
- enc[this.encodingLength - 1] |= point.getX().isOdd() ? 0x80 : 0;
- return enc;
- };
- EDDSA.prototype.decodePoint = function decodePoint(bytes) {
- bytes = utils.parseBytes(bytes);
- var lastIx = bytes.length - 1;
- var normed = bytes.slice(0, lastIx).concat(bytes[lastIx] & ~0x80);
- var xIsOdd = (bytes[lastIx] & 0x80) !== 0;
- var y = utils.intFromLE(normed);
- return this.curve.pointFromY(y, xIsOdd);
- };
- EDDSA.prototype.encodeInt = function encodeInt(num) {
- return num.toArray('le', this.encodingLength);
- };
- EDDSA.prototype.decodeInt = function decodeInt(bytes) {
- return utils.intFromLE(bytes);
- };
- EDDSA.prototype.isPoint = function isPoint(val) {
- return val instanceof this.pointClass;
- };
|