weierstrass, edwards: get rid of bigint literals. Closes gh-22

This commit is contained in:
Paul Miller 2023-03-28 17:01:00 +00:00
parent 3936449e7b
commit 618508d32c
No known key found for this signature in database
GPG Key ID: 697079DA6878B89B
6 changed files with 26 additions and 27 deletions

@ -5,11 +5,9 @@ import * as ut from './utils.js';
import { ensureBytes, FHash, Hex } from './utils.js'; import { ensureBytes, FHash, Hex } from './utils.js';
import { Group, GroupConstructor, wNAF, BasicCurve, validateBasic, AffinePoint } from './curve.js'; import { Group, GroupConstructor, wNAF, BasicCurve, validateBasic, AffinePoint } from './curve.js';
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n // Be friendly to bad ECMAScript parsers by not using bigint literals
const _0n = BigInt(0); // prettier-ignore
const _1n = BigInt(1); const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _8n = BigInt(8);
const _2n = BigInt(2);
const _8n = BigInt(8);
// Edwards curves must declare params a & d. // Edwards curves must declare params a & d.
export type CurveType = BasicCurve<bigint> & { export type CurveType = BasicCurve<bigint> & {
@ -111,7 +109,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
if (ctx.length || phflag) throw new Error('Contexts/pre-hash are not supported'); if (ctx.length || phflag) throw new Error('Contexts/pre-hash are not supported');
return data; return data;
}); // NOOP }); // NOOP
const inBig = (n: bigint) => typeof n === 'bigint' && 0n < n; // n in [1..] const inBig = (n: bigint) => typeof n === 'bigint' && _0n < n; // n in [1..]
const inRange = (n: bigint, max: bigint) => inBig(n) && inBig(max) && n < max; // n in [1..max-1] const inRange = (n: bigint, max: bigint) => inBig(n) && inBig(max) && n < max; // n in [1..max-1]
const in0MaskRange = (n: bigint) => n === _0n || inRange(n, MASK); // n in [0..MASK-1] const in0MaskRange = (n: bigint) => n === _0n || inRange(n, MASK); // n in [0..MASK-1]
function assertInRange(n: bigint, max: bigint) { function assertInRange(n: bigint, max: bigint) {

@ -275,7 +275,7 @@ export function FpPow<T>(f: IField<T>, num: T, power: bigint): T {
while (power > _0n) { while (power > _0n) {
if (power & _1n) p = f.mul(p, d); if (power & _1n) p = f.mul(p, d);
d = f.sqr(d); d = f.sqr(d);
power >>= 1n; power >>= _1n;
} }
return p; return p;
} }

@ -176,9 +176,9 @@ const DER = {
}, },
}; };
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n // Be friendly to bad ECMAScript parsers by not using bigint literals
const _0n = BigInt(0); // prettier-ignore
const _1n = BigInt(1); const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
export function weierstrassPoints<T>(opts: CurvePointsType<T>) { export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
const CURVE = validatePointOpts(opts); const CURVE = validatePointOpts(opts);
@ -365,7 +365,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
// Cost: 8M + 3S + 3*a + 2*b3 + 15add. // Cost: 8M + 3S + 3*a + 2*b3 + 15add.
double() { double() {
const { a, b } = CURVE; const { a, b } = CURVE;
const b3 = Fp.mul(b, 3n); const b3 = Fp.mul(b, _3n);
const { px: X1, py: Y1, pz: Z1 } = this; const { px: X1, py: Y1, pz: Z1 } = this;
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
let t0 = Fp.mul(X1, X1); // step 1 let t0 = Fp.mul(X1, X1); // step 1
@ -412,7 +412,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
const { px: X2, py: Y2, pz: Z2 } = other; const { px: X2, py: Y2, pz: Z2 } = other;
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
const a = CURVE.a; const a = CURVE.a;
const b3 = Fp.mul(CURVE.b, 3n); const b3 = Fp.mul(CURVE.b, _3n);
let t0 = Fp.mul(X1, X2); // step 1 let t0 = Fp.mul(X1, X2); // step 1
let t1 = Fp.mul(Y1, Y2); let t1 = Fp.mul(Y1, Y2);
let t2 = Fp.mul(Z1, Z2); let t2 = Fp.mul(Z1, Z2);
@ -1078,15 +1078,15 @@ export function weierstrass(curveDef: CurveType): CurveFn {
export function SWUFpSqrtRatio<T>(Fp: mod.IField<T>, Z: T) { export function SWUFpSqrtRatio<T>(Fp: mod.IField<T>, Z: T) {
// Generic implementation // Generic implementation
const q = Fp.ORDER; const q = Fp.ORDER;
let l = 0n; let l = _0n;
for (let o = q - 1n; o % 2n === 0n; o /= 2n) l += 1n; for (let o = q - _1n; o % _2n === _0n; o /= _2n) l += _1n;
const c1 = l; // 1. c1, the largest integer such that 2^c1 divides q - 1. const c1 = l; // 1. c1, the largest integer such that 2^c1 divides q - 1.
const c2 = (q - 1n) / 2n ** c1; // 2. c2 = (q - 1) / (2^c1) # Integer arithmetic const c2 = (q - _1n) / _2n ** c1; // 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
const c3 = (c2 - 1n) / 2n; // 3. c3 = (c2 - 1) / 2 # Integer arithmetic const c3 = (c2 - _1n) / _2n; // 3. c3 = (c2 - 1) / 2 # Integer arithmetic
const c4 = 2n ** c1 - 1n; // 4. c4 = 2^c1 - 1 # Integer arithmetic const c4 = _2n ** c1 - _1n; // 4. c4 = 2^c1 - 1 # Integer arithmetic
const c5 = 2n ** (c1 - 1n); // 5. c5 = 2^(c1 - 1) # Integer arithmetic const c5 = _2n ** (c1 - _1n); // 5. c5 = 2^(c1 - 1) # Integer arithmetic
const c6 = Fp.pow(Z, c2); // 6. c6 = Z^c2 const c6 = Fp.pow(Z, c2); // 6. c6 = Z^c2
const c7 = Fp.pow(Z, (c2 + 1n) / 2n); // 7. c7 = Z^((c2 + 1) / 2) const c7 = Fp.pow(Z, (c2 + _1n) / _2n); // 7. c7 = Z^((c2 + 1) / 2)
let sqrtRatio = (u: T, v: T): { isValid: boolean; value: T } => { let sqrtRatio = (u: T, v: T): { isValid: boolean; value: T } => {
let tv1 = c6; // 1. tv1 = c6 let tv1 = c6; // 1. tv1 = c6
let tv2 = Fp.pow(v, c4); // 2. tv2 = v^c4 let tv2 = Fp.pow(v, c4); // 2. tv2 = v^c4
@ -1106,7 +1106,7 @@ export function SWUFpSqrtRatio<T>(Fp: mod.IField<T>, Z: T) {
tv4 = Fp.cmov(tv5, tv4, isQR); // 16. tv4 = CMOV(tv5, tv4, isQR) tv4 = Fp.cmov(tv5, tv4, isQR); // 16. tv4 = CMOV(tv5, tv4, isQR)
// 17. for i in (c1, c1 - 1, ..., 2): // 17. for i in (c1, c1 - 1, ..., 2):
for (let i = c1; i > 1; i--) { for (let i = c1; i > 1; i--) {
let tv5 = 2n ** (i - 2n); // 18. tv5 = i - 2; 19. tv5 = 2^tv5 let tv5 = _2n ** (i - _2n); // 18. tv5 = i - 2; 19. tv5 = 2^tv5
let tvv5 = Fp.pow(tv4, tv5); // 20. tv5 = tv4^tv5 let tvv5 = Fp.pow(tv4, tv5); // 20. tv5 = tv4^tv5
const e1 = Fp.eql(tvv5, Fp.ONE); // 21. e1 = tv5 == 1 const e1 = Fp.eql(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
tv2 = Fp.mul(tv3, tv1); // 22. tv2 = tv3 * tv1 tv2 = Fp.mul(tv3, tv1); // 22. tv2 = tv3 * tv1
@ -1117,9 +1117,9 @@ export function SWUFpSqrtRatio<T>(Fp: mod.IField<T>, Z: T) {
} }
return { isValid: isQR, value: tv3 }; return { isValid: isQR, value: tv3 };
}; };
if (Fp.ORDER % 4n === 3n) { if (Fp.ORDER % _4n === _3n) {
// sqrt_ratio_3mod4(u, v) // sqrt_ratio_3mod4(u, v)
const c1 = (Fp.ORDER - 3n) / 4n; // 1. c1 = (q - 3) / 4 # Integer arithmetic const c1 = (Fp.ORDER - _3n) / _4n; // 1. c1 = (q - 3) / 4 # Integer arithmetic
const c2 = Fp.sqrt(Fp.neg(Z)); // 2. c2 = sqrt(-Z) const c2 = Fp.sqrt(Fp.neg(Z)); // 2. c2 = sqrt(-Z)
sqrtRatio = (u: T, v: T) => { sqrtRatio = (u: T, v: T) => {
let tv1 = Fp.sqr(v); // 1. tv1 = v^2 let tv1 = Fp.sqr(v); // 1. tv1 = v^2
@ -1135,7 +1135,7 @@ export function SWUFpSqrtRatio<T>(Fp: mod.IField<T>, Z: T) {
}; };
} }
// No curves uses that // No curves uses that
// if (Fp.ORDER % 8n === 5n) // sqrt_ratio_5mod8 // if (Fp.ORDER % _8n === _5n) // sqrt_ratio_5mod8
return sqrtRatio; return sqrtRatio;
} }
// From draft-irtf-cfrg-hash-to-curve-16 // From draft-irtf-cfrg-hash-to-curve-16

@ -204,7 +204,7 @@ function map_to_curve_elligator2_curve25519(u: bigint) {
let y = Fp.cmov(y2, y1, e3); // 36. y = CMOV(y2, y1, e3) # If e3, y = y1, else y = y2 let y = Fp.cmov(y2, y1, e3); // 36. y = CMOV(y2, y1, e3) # If e3, y = y1, else y = y2
let e4 = Fp.isOdd(y); // 37. e4 = sgn0(y) == 1 # Fix sign of y let e4 = Fp.isOdd(y); // 37. e4 = sgn0(y) == 1 # Fix sign of y
y = Fp.cmov(y, Fp.neg(y), e3 !== e4); // 38. y = CMOV(y, -y, e3 XOR e4) y = Fp.cmov(y, Fp.neg(y), e3 !== e4); // 38. y = CMOV(y, -y, e3 XOR e4)
return { xMn: xn, xMd: xd, yMn: y, yMd: 1n }; // 39. return (xn, xd, y, 1) return { xMn: xn, xMd: xd, yMn: y, yMd: _1n }; // 39. return (xn, xd, y, 1)
} }
const ELL2_C1_EDWARDS = FpSqrtEven(Fp, Fp.neg(BigInt(486664))); // sgn0(c1) MUST equal 0 const ELL2_C1_EDWARDS = FpSqrtEven(Fp, Fp.neg(BigInt(486664))); // sgn0(c1) MUST equal 0

@ -54,6 +54,7 @@ function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
} }
const Fp = Field(ed448P, 456, true); const Fp = Field(ed448P, 456, true);
const _4n = BigInt(4);
const ED448_DEF = { const ED448_DEF = {
// Param: a // Param: a
@ -195,10 +196,10 @@ function map_to_curve_elligator2_edwards448(u: bigint) {
xEn = Fp.mul(xEn, xd2); // 9. xEn = xEn * xd2 xEn = Fp.mul(xEn, xd2); // 9. xEn = xEn * xd2
xEn = Fp.mul(xEn, yd); // 10. xEn = xEn * yd xEn = Fp.mul(xEn, yd); // 10. xEn = xEn * yd
xEn = Fp.mul(xEn, yn); // 11. xEn = xEn * yn xEn = Fp.mul(xEn, yn); // 11. xEn = xEn * yn
xEn = Fp.mul(xEn, 4n); // 12. xEn = xEn * 4 xEn = Fp.mul(xEn, _4n); // 12. xEn = xEn * 4
tv2 = Fp.mul(tv2, xn2); // 13. tv2 = tv2 * xn2 tv2 = Fp.mul(tv2, xn2); // 13. tv2 = tv2 * xn2
tv2 = Fp.mul(tv2, yd2); // 14. tv2 = tv2 * yd2 tv2 = Fp.mul(tv2, yd2); // 14. tv2 = tv2 * yd2
let tv3 = Fp.mul(yn2, 4n); // 15. tv3 = 4 * yn2 let tv3 = Fp.mul(yn2, _4n); // 15. tv3 = 4 * yn2
let tv1 = Fp.add(tv3, yd2); // 16. tv1 = tv3 + yd2 let tv1 = Fp.add(tv3, yd2); // 16. tv1 = tv3 + yd2
tv1 = Fp.mul(tv1, xd4); // 17. tv1 = tv1 * xd4 tv1 = Fp.mul(tv1, xd4); // 17. tv1 = tv1 * xd4
let xEd = Fp.add(tv1, tv2); // 18. xEd = tv1 + tv2 let xEd = Fp.add(tv1, tv2); // 18. xEd = tv1 + tv2

@ -131,7 +131,7 @@ function lift_x(x: bigint): PointType<bigint> {
const xx = modP(x * x); const xx = modP(x * x);
const c = modP(xx * x + BigInt(7)); // Let c = x³ + 7 mod p. const c = modP(xx * x + BigInt(7)); // Let c = x³ + 7 mod p.
let y = sqrtMod(c); // Let y = c^(p+1)/4 mod p. let y = sqrtMod(c); // Let y = c^(p+1)/4 mod p.
if (y % 2n !== 0n) y = modP(-y); // Return the unique point P such that x(P) = x and if (y % _2n !== _0n) y = modP(-y); // Return the unique point P such that x(P) = x and
const p = new Point(x, y, _1n); // y(P) = y if y mod 2 = 0 or y(P) = p-y otherwise. const p = new Point(x, y, _1n); // y(P) = y if y mod 2 = 0 or y(P) = p-y otherwise.
p.assertValidity(); p.assertValidity();
return p; return p;