@bsv/sdk
Version:
BSV Blockchain Software Development Kit
137 lines (120 loc) • 5.04 kB
text/typescript
import Mersenne from './Mersenne.js'
import BigNumber from './BigNumber.js'
/**
* A class representing K-256, a prime number with optimizations, specifically used in the secp256k1 curve.
* It extends the functionalities of the Mersenne class.
* K-256 prime is represented as 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f'
*
* @class K256
* @extends {Mersenne}
*
* @example
* const k256 = new K256();
*/
export default class K256 extends Mersenne {
/**
* Constructor for the K256 class.
* Creates an instance of K256 using the super constructor from Mersenne.
*
* @constructor
*
* @example
* const k256 = new K256();
*/
constructor () {
super(
'k256',
'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f'
)
}
/**
* Splits a BigNumber into a new BigNumber based on specific computation
* rules. This method modifies the input and output big numbers.
*
* @method split
* @param input - The BigNumber to be split.
* @param output - The BigNumber that results from the split.
*
* @example
* const input = new BigNumber(3456);
* const output = new BigNumber(0);
* k256.split(input, output);
*/
split (input: BigNumber, output: BigNumber): void {
const mask = 0x3fffff // 22 bits
const inputWords = input.words // Access via getter
const inputNominalLength = input.length // Access via getter, respects _nominalWordLength
const outLen = Math.min(inputNominalLength, 9)
const tempOutputWords = new Array(outLen + (inputNominalLength > 9 ? 1 : 0)).fill(0)
for (let i = 0; i < outLen; i++) {
tempOutputWords[i] = inputWords[i]
}
let currentOutputWordCount = outLen
if (inputNominalLength <= 9) {
const finalOutputWords = new Array(currentOutputWordCount)
for (let i = 0; i < currentOutputWordCount; ++i) finalOutputWords[i] = tempOutputWords[i]
output.words = finalOutputWords // Use setter
input.words = [0] // Use setter to set to 0
return
}
// Shift by 9 limbs
let prev = inputWords[9]
tempOutputWords[currentOutputWordCount++] = prev & mask
const finalOutputWords = new Array(currentOutputWordCount)
for (let i = 0; i < currentOutputWordCount; ++i) finalOutputWords[i] = tempOutputWords[i]
output.words = finalOutputWords // Use setter for output
// For input modification
const tempInputNewWords = new Array(Math.max(1, inputNominalLength - 9)).fill(0)
let currentInputNewWordCount = 0
for (let i = 10; i < inputNominalLength; i++) {
const next = inputWords[i] | 0
if (currentInputNewWordCount < tempInputNewWords.length) { // Boundary check
tempInputNewWords[currentInputNewWordCount++] = ((next & mask) << 4) | (prev >>> 22)
}
prev = next
}
prev >>>= 22
if (currentInputNewWordCount < tempInputNewWords.length) { // Boundary check
tempInputNewWords[currentInputNewWordCount++] = prev
} else if (prev !== 0 && tempInputNewWords.length > 0) { // If prev is non-zero but no space, this is an issue.
// This case implies original logic might have relied on array auto-expansion or specific length handling
// For safety, if there's still a carry and no space, the array should have been bigger.
// However, the original logic `input.length -= 9` suggests truncation.
}
const finalInputNewWords = new Array(currentInputNewWordCount)
for (let i = 0; i < currentInputNewWordCount; ++i) finalInputNewWords[i] = tempInputNewWords[i]
input.words = finalInputNewWords // Use setter, which will strip and set magnitude
}
/**
* Multiplies a BigNumber ('num') with the constant 'K' in-place and returns the result.
* 'K' is equal to 0x1000003d1 or in decimal representation: [ 64, 977 ].
*
* @method imulK
* @param num - The BigNumber to multiply with K.
* @returns Returns the mutated BigNumber after multiplication.
*
* @example
* const number = new BigNumber(12345);
* const result = k256.imulK(number);
*/
imulK (num: BigNumber): BigNumber {
const currentWords = num.words // Get current words based on _magnitude and _nominalWordLength
const originalNominalLength = num.length // Getter
const newNominalLength = originalNominalLength + 2
const tempWords = new Array(newNominalLength).fill(0)
for (let i = 0; i < originalNominalLength; i++) {
tempWords[i] = currentWords[i]
}
// tempWords is now effectively num.words expanded with zeroes
let lo = 0
for (let i = 0; i < newNominalLength; i++) { // Iterate up to new expanded length
const w = tempWords[i] | 0
lo += w * 0x3d1 // 0x3d1 = 977
tempWords[i] = lo & 0x3ffffff // 26-bit mask
lo = w * 0x40 + ((lo / 0x4000000) | 0) // 0x40 = 64. 0x4000000 = 2^26
}
num.words = tempWords // Use setter to re-initialize from tempWords
// The setter will handle _magnitude, _sign, _nominalWordLength, and strip.
return num
}
}