Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
nichoth committed Dec 15, 2024
1 parent fbb94e5 commit 0502f56
Show file tree
Hide file tree
Showing 14 changed files with 286 additions and 2,278 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
"miller-rabin": "^4.0.0"
"bn.js": "^5.2.1",
"miller-rabin": "^4.0.0",
"uint8arrays": "^5.1.0"
},
"devDependencies": {
"@substrate-system/tapzero": "^0.10.5",
Expand Down
289 changes: 193 additions & 96 deletions src/dh.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,209 @@
import MillerRabin from 'miller-rabin'
import BN from './bn.js'
import primes from './generatePrime.js'
import randomBytes from '@bicycle-codes/randombytes'
import BN from 'bn.js'
import {
concat,
fromString,
type SupportedEncodings,
toString
} from 'uint8arrays'
import primes from './generate-prime.js'

const millerRabin = new MillerRabin()
const TWENTYFOUR = new BN(24)
const ELEVEN = new BN(11)
const TEN = new BN(10)
const THREE = new BN(3)
const SEVEN = new BN(7)
module.exports = DH

function setPublicKey (pub, enc) {
enc = enc || 'utf8'
if (!Buffer.isBuffer(pub)) {
pub = new Buffer(pub, enc)
export class DH {
_pub:BN
_priv:BN
_prime:BN
__prime:BN
_primeLen:BN
_primeCode?:number
_gen:BN
__gen:Uint8Array|null = null
_malleable:boolean

static BN = BN

constructor (prime, generator, malleable?:boolean) {
this.setGenerator(generator)
this._malleable = !!malleable
this.__prime = new BN(prime)
this._primeLen = prime.length
this._pub = undefined
this._priv = undefined
this._primeCode = undefined
if (malleable) {
this._malleable = true
// this.setPublicKey = setPublicKey
// this.setPrivateKey = setPrivateKey
} else {
this._primeCode = 8
this._malleable = false
}
}

computeSecret (other:BN):Uint8Array {
other = new BN(other)
other = other.toRed(this._prime)
const secret = other.redPow(this._priv).fromRed()
// let out = new Buffer(secret.toArray())
let out = new Uint8Array(secret.toArray())
const prime = this.getPrime()
if (out.length < prime.length) {
// const front = new Buffer(prime.length - out.length)
const front = new Uint8Array(prime.length - out.length)
front.fill(0)
// out = Buffer.concat([front, out])
out = concat([front, out])
// out = Buffer.concat([front, out])
}

return out
}

getPrime (enc?:SupportedEncodings) {
return formatReturnValue(this.__prime, enc)
}

getPublicKey (enc?:SupportedEncodings) {
return formatReturnValue(this._pub, enc)
}

getPrivateKey (enc?:SupportedEncodings) {
return formatReturnValue(this._priv, enc)
}

generateKeys () {
if (!this._priv) {
this._priv = new BN(randomBytes(this._primeLen))
}
this._pub = this._gen.toRed(this._prime).redPow(this._priv).fromRed()
return this.getPublicKey()
}

setPublicKey (pub:Uint8Array|string, enc?:SupportedEncodings) {
if (!this._malleable) throw new Error('not malleable')
enc = enc || 'utf8'
if (!(pub instanceof Uint8Array)) {
pub = fromString(pub, enc)
}
this._pub = new BN(pub)

return this
}

setPrivateKey (priv:string|Uint8Array, enc) {
if (!this._malleable) throw new Error('not malleable')
enc = enc || 'utf8'
if (!(priv instanceof Uint8Array)) {
priv = fromString(priv, enc)
}
this._priv = new BN(priv)

return this
}

setGenerator (gen:Uint8Array|string, enc?:SupportedEncodings) {
enc = enc || 'utf8'
if (!(gen instanceof Uint8Array)) {
gen = fromString(gen, enc)
}
this.__gen = gen
this._gen = new BN(gen)
return this
}

getGenerator (enc?:SupportedEncodings) {
return formatReturnValue(this._gen, enc)
}
this._pub = new BN(pub)
return this
}

function setPrivateKey (priv, enc) {
enc = enc || 'utf8'
if (!Buffer.isBuffer(priv)) {
priv = new Buffer(priv, enc)
Object.defineProperty(DH.prototype, 'verifyError', {
enumerable: true,
get: function () {
if (typeof this._primeCode !== 'number') {
this._primeCode = checkPrime(this.__prime, this.__gen)
}
return this._primeCode
}
})

// export function oldDH (prime, generator, malleable) {
// this.setGenerator(generator)
// this.__prime = new BN(prime)
// this._prime = BN.mont(this.__prime)
// this._primeLen = prime.length
// this._pub = undefined
// this._priv = undefined
// this._primeCode = undefined
// if (malleable) {
// this.setPublicKey = setPublicKey
// this.setPrivateKey = setPrivateKey
// } else {
// this._primeCode = 8
// }
// }

// DH.prototype.generateKeys = function () {
// if (!this._priv) {
// this._priv = new BN(randomBytes(this._primeLen))
// }
// this._pub = this._gen.toRed(this._prime).redPow(this._priv).fromRed()
// return this.getPublicKey()
// }

// DH.prototype.computeSecret = function (other) {
// other = new BN(other)
// other = other.toRed(this._prime)
// const secret = other.redPow(this._priv).fromRed()
// let out = new Buffer(secret.toArray())
// const prime = this.getPrime()
// if (out.length < prime.length) {
// const front = new Buffer(prime.length - out.length)
// front.fill(0)
// out = Buffer.concat([front, out])
// }
// return out
// }

// DH.prototype.getPublicKey = function getPublicKey (enc) {
// return formatReturnValue(this._pub, enc)
// }

// DH.prototype.getPrivateKey = function getPrivateKey (enc) {
// return formatReturnValue(this._priv, enc)
// }

// DH.prototype.getPrime = function (enc) {
// return formatReturnValue(this.__prime, enc)
// }

// DH.prototype.getGenerator = function (enc) {
// return formatReturnValue(this._gen, enc)
// }

// DH.prototype.setGenerator = function (gen, enc) {
// enc = enc || 'utf8'
// if (!Buffer.isBuffer(gen)) {
// gen = new Buffer(gen, enc)
// }
// this.__gen = gen
// this._gen = new BN(gen)
// return this
// }

function formatReturnValue (bn:BN, enc?:SupportedEncodings) {
const buf = new Uint8Array(bn.toArray())
if (!enc) {
return buf
} else {
return toString(buf, enc)
}
this._priv = new BN(priv)
return this
}

const primeCache = {}
Expand Down Expand Up @@ -81,84 +259,3 @@ function checkPrime (prime, generator) {
primeCache[hex] = error
return error
}

export function DH (prime, generator, malleable) {
this.setGenerator(generator)
this.__prime = new BN(prime)
this._prime = BN.mont(this.__prime)
this._primeLen = prime.length
this._pub = undefined
this._priv = undefined
this._primeCode = undefined
if (malleable) {
this.setPublicKey = setPublicKey
this.setPrivateKey = setPrivateKey
} else {
this._primeCode = 8
}
}
Object.defineProperty(DH.prototype, 'verifyError', {
enumerable: true,
get: function () {
if (typeof this._primeCode !== 'number') {
this._primeCode = checkPrime(this.__prime, this.__gen)
}
return this._primeCode
}
})
DH.prototype.generateKeys = function () {
if (!this._priv) {
this._priv = new BN(randomBytes(this._primeLen))
}
this._pub = this._gen.toRed(this._prime).redPow(this._priv).fromRed()
return this.getPublicKey()
}

DH.prototype.computeSecret = function (other) {
other = new BN(other)
other = other.toRed(this._prime)
const secret = other.redPow(this._priv).fromRed()
let out = new Buffer(secret.toArray())
const prime = this.getPrime()
if (out.length < prime.length) {
const front = new Buffer(prime.length - out.length)
front.fill(0)
out = Buffer.concat([front, out])
}
return out
}

DH.prototype.getPublicKey = function getPublicKey (enc) {
return formatReturnValue(this._pub, enc)
}

DH.prototype.getPrivateKey = function getPrivateKey (enc) {
return formatReturnValue(this._priv, enc)
}

DH.prototype.getPrime = function (enc) {
return formatReturnValue(this.__prime, enc)
}

DH.prototype.getGenerator = function (enc) {
return formatReturnValue(this._gen, enc)
}

DH.prototype.setGenerator = function (gen, enc) {
enc = enc || 'utf8'
if (!Buffer.isBuffer(gen)) {
gen = new Buffer(gen, enc)
}
this.__gen = gen
this._gen = new BN(gen)
return this
}

function formatReturnValue (bn, enc) {
const buf = new Buffer(bn.toArray())
if (!enc) {
return buf
} else {
return buf.toString(enc)
}
}
31 changes: 17 additions & 14 deletions src/generatePrime.ts → src/generate-prime.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
const randomBytes = require('randombytes')
module.exports = findPrime
findPrime.simpleSieve = simpleSieve
findPrime.fermatTest = fermatTest
const BN = require('bn.js')
import { randomBytes } from '@bicycle-codes/randombytes'
import BN from 'bn.js'
import MillerRabin from 'miller-rabin'
const TWENTYFOUR = new BN(24)
const MillerRabin = require('miller-rabin')
const millerRabin = new MillerRabin()
const ONE = new BN(1)
const TWO = new BN(2)
const FIVE = new BN(5)
const SIXTEEN = new BN(16)
const EIGHT = new BN(8)
const TEN = new BN(10)
const THREE = new BN(3)
const SEVEN = new BN(7)
const ELEVEN = new BN(11)
const FOUR = new BN(4)
const TWELVE = new BN(12)
let primes = null

let primes:number[]|null = null

findPrime.simpleSieve = simpleSieve
findPrime.fermatTest = fermatTest

function _getPrimes () {
if (primes !== null) { return primes }
if (primes !== null) {
return primes
}

const limit = 0x100000
const res = []
const res:number[] = []
res[0] = 2
for (let i = 1, k = 3; k < limit; k += 2) {
const sqrt = Math.ceil(Math.sqrt(k))
// eslint-disable-next-line no-var
for (var j = 0; j < i && res[j] <= sqrt; j++) {
if (k % res[j] === 0) { break }
}
Expand All @@ -35,6 +35,7 @@ function _getPrimes () {

res[i++] = k
}

primes = res
return res
}
Expand All @@ -60,7 +61,7 @@ function fermatTest (p) {
return TWO.toRed(red).redPow(p.subn(1)).fromRed().cmpn(1) === 0
}

function findPrime (bits, gen) {
export function findPrime (bits, gen) {
if (bits < 16) {
// this is what openssl does
if (gen === 2 || gen === 5) {
Expand Down Expand Up @@ -101,3 +102,5 @@ function findPrime (bits, gen) {
}
}
}

export default findPrime
Loading

0 comments on commit 0502f56

Please sign in to comment.