<commit_before>/*!
 * bip151.js - peer-to-peer communication encryption.
 * Copyright (c) 2016, <NAME> (MIT License).
 * https://github.com/bcoin-org/bcoin
 * Resources:
 *   https://github.com/bitcoin/bips/blob/master/bip-0151.mediawiki
 *   https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.chacha20poly1305
 *   https://github.com/openssh/openssh-portable/blob/master/cipher-chachapoly.c
 *   https://github.com/openssh/openssh-portable/blob/master/cipher.c
 *   https://github.com/openssh/openssh-portable/blob/master/packet.c
 */

'use strict';

var EventEmitter = require('events').EventEmitter;
var bcoin = require('./env');
var utils = require('./utils');
var assert = utils.assert;
var constants = bcoin.protocol.constants;
var chachapoly = require('./chachapoly');

/*
 * Constants
 */

var HKDF_SALT = new Buffer('bitcoinechd' /* ecHd (sic?) */, 'ascii');
var INFO_KEY1 = new Buffer('BitcoinK1', 'ascii');
var INFO_KEY2 = new Buffer('BitcoinK2', 'ascii');
var INFO_SID = new Buffer('BitcoinSessionID', 'ascii');

/**
 * Represents a BIP151 input or output stream.
 * @exports BIP151Stream
 * @constructor
 * @param {Number} cipher
 * @param {Buffer?} key
 * @property {Buffer} publicKey
 * @property {Buffer} privateKey
 * @property {Number} cipher
 * @property {Buffer} prk
 * @property {Buffer} k1
 * @property {Buffer} k2
 * @property {Buffer} sid
 * @property {ChaCha20} chacha
 * @property {AEAD} aead
 * @property {Buffer} tag
 * @property {Number} seq
 * @property {Number} highWaterMark
 * @property {Number} processed
 * @property {Number} lastKey
 */

function BIP151Stream(cipher, key) {
  if (!(this instanceof BIP151Stream))
    return new BIP151Stream(cipher, key);

  EventEmitter.call(this);

  this.publicKey = null;
  this.privateKey = key || bcoin.ec.generatePrivateKey();
  this.cipher = cipher || 0;
  this.secret = null;
  this.prk = null;
  this.k1 = null;
  this.k2 = null;
  this.sid = null;

  assert(this.cipher === 0, 'Unknown cipher type.');

  this.chacha = new chachapoly.ChaCha20();
  this.aead = new chachapoly.AEAD();
  this.tag = null;
  this.seqHi = 0;
  this.seqLo = 0;
  this.iv = new Buffer(12);
  this.iv.fill(0);

  this.highWaterMark = 1024 * (1 << 20);
  this.processed = 0;
  this.lastRekey = 0;

  this.pending = [];
  this.pendingTotal = 0;
  this.waiting = 0;
}

utils.inherits(BIP151Stream, EventEmitter);

/**
 * Initialize the stream with peer's public key.
 * Computes ecdh secret and chacha keys.
 * @param {Buffer} publicKey
 */

BIP151Stream.prototype.init = function init(publicKey) {
  var p = bcoin.writer();

  this.publicKey = publicKey;
  this.secret = bcoin.ec.ecdh(this.publicKey, this.privateKey);

  p.writeBytes(this.secret);
  p.writeU8(this.cipher);

  this.prk = utils.hkdfExtract(p.render(), HKDF_SALT, 'sha256');
  this.k1 = utils.hkdfExpand(this.prk, INFO_KEY1, 32, 'sha256');
  this.k2 = utils.hkdfExpand(this.prk, INFO_KEY2, 32, 'sha256');
  this.sid = utils.hkdfExpand(this.prk, INFO_SID, 32, 'sha256');

  this.seqHi = 0;
  this.seqLo = 0;

  this.update();

  this.chacha.init(this.k1, this.iv);
  this.aead.init(this.k2, this.iv);

  this.lastRekey = utils.now();
};

/**
 * Add buffer size to `processed`,
 * check whether we need to rekey.
 * @param {Buffer} data
 */

BIP151Stream.prototype.maybeRekey = function maybeRekey(data) {
  var now = utils.now();

  this.processed += data.length;

  if (now >= this.lastRekey + 10
      || this.processed >= this.highWaterMark) {
    this.lastRekey = now;
    this.processed = 0;
    this.emit('rekey');
    this.rekey();
  }
};

/**
 * Generate new chacha keys with `key = HASH256(key)`.
 * This will reinitialize the state of both ciphers.
 */

BIP151Stream.prototype.rekey = function rekey() {
  assert(this.prk, 'Cannot rekey before initialization.');

  // All state is reinitialized
  // aside from the sequence number.
  this.k1 = utils.hash256(this.k1);
  this.k2 = utils.hash256(this.k2);

  this.chacha.init(this.k1, this.iv);
  this.aead.init(this.k2, this.iv);
};

/**
 * Increment packet sequence number and update IVs
 * (note, sequence number overflows after 2^64-1).
 * The IV will be updated without reinitializing
 * cipher state.
 */

BIP151Stream.prototype.sequence = function sequence() {
  // Wrap sequence number a la openssh.
  if (++this.seqLo === 0x100000000) {
    this.seqLo = 0;
    if (++this.seqHi === 0x100000000)
      this.seqHi = 0;
  }

  this.update();

  // State of the ciphers is
  // unaltered aside from the iv.
  this.chacha.init(null, this.iv);
  this.aead.init(null, this.iv);
};

/**
 * Render the IV necessary for cipher streams.
 * @returns {Buffer}
 */

BIP151Stream.prototype.update = function update() {
  this.iv.writeUInt32LE(this.seqLo, 0, true);
  this.iv.writeUInt32LE(this.seqHi, 4, true);
  return this.iv;
};<commit_msg>bip151: 32 bit sequence and 64 bit iv.<commit_after>/*!
 * bip151.js - peer-to-peer communication encryption.
 * Copyright (c) 2016, <NAME> (MIT License).
 * https://github.com/bcoin-org/bcoin
 * Resources:
 *   https://github.com/bitcoin/bips/blob/master/bip-0151.mediawiki
 *   https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.chacha20poly1305
 *   https://github.com/openssh/openssh-portable/blob/master/cipher-chachapoly.c
 *   https://github.com/openssh/openssh-portable/blob/master/cipher.c
 *   https://github.com/openssh/openssh-portable/blob/master/packet.c
 */

'use strict';

var EventEmitter = require('events').EventEmitter;
var bcoin = require('./env');
var utils = require('./utils');
var assert = utils.assert;
var constants = bcoin.protocol.constants;
var chachapoly = require('./chachapoly');

/*
 * Constants
 */

var HKDF_SALT = new Buffer('bitcoinechd' /* ecHd (sic?) */, 'ascii');
var INFO_KEY1 = new Buffer('BitcoinK1', 'ascii');
var INFO_KEY2 = new Buffer('BitcoinK2', 'ascii');
var INFO_SID = new Buffer('BitcoinSessionID', 'ascii');

/**
 * Represents a BIP151 input or output stream.
 * @exports BIP151Stream
 * @constructor
 * @param {Number} cipher
 * @param {Buffer?} key
 * @property {Buffer} publicKey
 * @property {Buffer} privateKey
 * @property {Number} cipher
 * @property {Buffer} prk
 * @property {Buffer} k1
 * @property {Buffer} k2
 * @property {Buffer} sid
 * @property {ChaCha20} chacha
 * @property {AEAD} aead
 * @property {Buffer} tag
 * @property {Number} seq
 * @property {Number} highWaterMark
 * @property {Number} processed
 * @property {Number} lastKey
 */

function BIP151Stream(cipher, key) {
  if (!(this instanceof BIP151Stream))
    return new BIP151Stream(cipher, key);

  EventEmitter.call(this);

  this.publicKey = null;
  this.privateKey = key || bcoin.ec.generatePrivateKey();
  this.cipher = cipher || 0;
  this.secret = null;
  this.prk = null;
  this.k1 = null;
  this.k2 = null;
  this.sid = null;

  assert(this.cipher === 0, 'Unknown cipher type.');

  this.chacha = new chachapoly.ChaCha20();
  this.aead = new chachapoly.AEAD();
  this.tag = null;
  this.seq = 0;
  this.iv = new Buffer(8);
  this.iv.fill(0);

  this.highWaterMark = 1024 * (1 << 20);
  this.processed = 0;
  this.lastRekey = 0;

  this.pending = [];
  this.pendingTotal = 0;
  this.waiting = 0;
}

utils.inherits(BIP151Stream, EventEmitter);

/**
 * Initialize the stream with peer's public key.
 * Computes ecdh secret and chacha keys.
 * @param {Buffer} publicKey
 */

BIP151Stream.prototype.init = function init(publicKey) {
  var p = bcoin.writer();

  this.publicKey = publicKey;
  this.secret = bcoin.ec.ecdh(this.publicKey, this.privateKey);

  p.writeBytes(this.secret);
  p.writeU8(this.cipher);

  this.prk = utils.hkdfExtract(p.render(), HKDF_SALT, 'sha256');
  this.k1 = utils.hkdfExpand(this.prk, INFO_KEY1, 32, 'sha256');
  this.k2 = utils.hkdfExpand(this.prk, INFO_KEY2, 32, 'sha256');
  this.sid = utils.hkdfExpand(this.prk, INFO_SID, 32, 'sha256');

  this.seq = 0;

  this.update();

  this.chacha.init(this.k1, this.iv);
  this.aead.init(this.k2, this.iv);

  this.lastRekey = utils.now();
};

/**
 * Add buffer size to `processed`,
 * check whether we need to rekey.
 * @param {Buffer} data
 */

BIP151Stream.prototype.maybeRekey = function maybeRekey(data) {
  var now = utils.now();

  this.processed += data.length;

  if (now >= this.lastRekey + 10
      || this.processed >= this.highWaterMark) {
    this.lastRekey = now;
    this.processed = 0;
    this.emit('rekey');
    this.rekey();
  }
};

/**
 * Generate new chacha keys with `key = HASH256(key)`.
 * This will reinitialize the state of both ciphers.
 */

BIP151Stream.prototype.rekey = function rekey() {
  assert(this.prk, 'Cannot rekey before initialization.');

  // All state is reinitialized
  // aside from the sequence number.
  this.k1 = utils.hash256(this.k1);
  this.k2 = utils.hash256(this.k2);

  this.chacha.init(this.k1, this.iv);
  this.aead.init(this.k2, this.iv);
};

/**
 * Increment packet sequence number and update IVs
 * (note, sequence number overflows after 2^64-1).
 * The IV will be updated without reinitializing
 * cipher state.
 */

BIP151Stream.prototype.sequence = function sequence() {
  // Wrap sequence number a la openssh.
  if (++this.seq === 0x100000000)
    this.seq = 0;

  this.update();

  // State of the ciphers is
  // unaltered aside from the iv.
  this.chacha.init(null, this.iv);
  this.aead.init(null, this.iv);
};

/**
 * Render the IV necessary for cipher streams.
 * @returns {Buffer}
 */

BIP151Stream.prototype.update = function update() {
  this.iv.writeUInt32LE(this.seq, 4, true);
  return this.iv;
};
{'fraction_non_alphanumeric': 0.15508189836203276, 'fraction_numerical': 0.031919361612767747, 'mean_word_length': 3.6828908554572273, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 12, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 3, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3581572', 'n_tokens_mistral': 3678, 'n_tokens_neox': 3389, 'n_words': 785}