#typescript #digital-signature #bitcoin #modulo #ecdsa
Вопрос:
Я глубоко погружаюсь в биткойн и то, как он работает. В настоящее время я изучаю эллиптические кривые, подписи и проверки.
Я читаю инструкции по алгоритму генерации подписи.
В нем говорится::
Чтобы Алиса подписала сообщение m
, она выполняет следующие действия:
- Вычислять
e=HASH(m)
. (Здесь ХЭШ-это криптографическая хэш-функция, такая как SHA-2, с выводом, преобразованным в целое число.) - Пусть
z
будутL_n
крайние левые битыe
, гдеL_n
-длина бита группового порядкаn
. (Обратите внимание, что этоz
может быть большеn
, но не больше.)
Я не понимаю обоих предложений из 2.
Допустим, у меня есть hash
такой:
import { keccakFromString } from 'ethereumjs-util';
// This is Wikipedia's `n`
const BTC_PRIME_MODULO =
2n ** 256n -
2n ** 32n -
2n ** 9n -
2n ** 8n -
2n ** 7n -
2n ** 6n -
2n ** 4n -
1n;
const message = 'Learning blockchain development is fun.';
const hash = keccakFromString(message).toString('hex'); // `e` from Wikipedia
const hexToBigInt = (hex: string) => BigInt('0x' hex);
const bigIntToBinary = (int: bigint) => int.toString(2);
type getFirstNChars = (numberOfChars: number) => (string: string) => string;
const getFirstNChars: getFirstNChars = n => string => string.slice(0, n);
const getFirst256Chars = getFirstNChars(256);
const binaryToBigInt = (binary: string) => BigInt('0b' binary);
const get256LeftmostBits = pipe(
hexToBigInt,
bigIntToBinary,
getFirst256Chars,
binaryToBigInt,
);
const z = get256LeftmostBits(hash) // ... Is this correct?
Как мне теперь добраться z
?
Является ли групповой порядок биткоина FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
и, следовательно, длина бита 256?
И означает ли « z
может быть больше n
, но не длиннее», что это z
может быть BTC_PRIME_MODULO 1n
, поэтому оно больше, но имеет столько же цифр? Как может z
быть больше, если его n осталось больше всего битов?
More context:
I’m trying to implement sign
based on that Wikipedia article, and here is what I have so far:
const BITCOIN_GENERATOR_POINT: EllipticCurvePoint = {
x: 55_066_263_022_277_343_669_578_718_895_168_534_326_250_603_453_777_594_175_500_187_360_389_116_729_240n,
y: 32_670_510_020_758_816_978_083_085_130_507_043_184_471_273_380_659_243_275_938_904_335_757_337_482_424n,
};
const generateRandomBigInt = () =>
BigInt(`0x${randomBytes(32).toString('hex')}`);
const getK = pipe(
generateRandomBigInt,
maybeReducedModulo(BTC_PRIME_MODULO - 1n),
);
type sign = (privateKey: string, message: string) => string;
const sign: sign = (privateKey, message) => {
const privateKeyBigInt = BigInt(privateKey);
const hash = keccakFromString(message).toString('hex');
let r = 0n;
let s = 0n;
const z = get256LeftmostBits(hash); // I'm unsure whether this is correct 🤔
while (r === 0n || s === 0n) {
const k = getK();
const p1 = multiplyWithBasePoint(k);
r = maybeReduceByBTCPrimeModulo(p1.x);
s = maybeReduceByBTCPrimeModulo(
invertByBTCPrimeModulo(k) * (z r * privateKeyBigInt),
);
}
return ''; // ... need to properly concat r and s ...
};
где
maybeReducedModulo
даноa
иb
вычисляетa % b
, но добавляетb
, еслиa
отрицательно.multiplyWithBasePoint
умножается с помощью точки генератора БиткойновG
.- и
invertByBTCPrimeModulo
вычисляет модульную мультипликативную обратную величину сBTC_PRIME_MODULO
помощью .
Комментарии:
1. В случае кривой
secp256k1
, которая используется в биткойне и большинстве криптовалют, длина бита равна 256. Длина хэша также равна 256 (в случае биткоина это двойной sha256, в случае эфириума-keccak). Вам не нужно ничего урезать.z
может быть больше , чемn
, но вероятность того, что это произойдет, почти ничтожна. В этом случае с EC crypto не произойдет ничего особенного.2. @Zergatul В этом есть смысл, вау, спасибо!