Skip to content

Commit

Permalink
v3.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
pur3miish committed Nov 10, 2024
1 parent 3980701 commit 64ab0e5
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 49 deletions.
6 changes: 6 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Antelope ECC Changelog

## 3.0.1

### Patch

- Fixed recid bug that was causing webauthn signatures to fail.

## 3.0.0

### Major
Expand Down
11 changes: 8 additions & 3 deletions create_wa_public_key.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,19 @@ export default async function createWebAuthnKey({
relayingParty,
challenge,
}) {
if (!navigator?.credentials?.create)
throw new Error("Browser does not support webauthn.");
const cred = await navigator.credentials.create({
publicKey: {
rp: { id: relayingParty, name: relayingParty },
user: { id, name: email, displayName },
pubKeyCredParams: [{ type: "public-key", alg: -7 }],
pubKeyCredParams: [
{ type: "public-key", alg: -7 },
{ type: "public-key", alg: -257 },
],
attestation: "direct",
timeout: 60000,
challenge,
timeout: 6e4,
challenge: challenge.buffer,
},
});

Expand Down
24 changes: 14 additions & 10 deletions create_wa_signature.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,22 @@ export default async function createWebAuthnSignature(credential_ids, hash) {
)
: hash;

const assertation = await navigator.credentials.get({
const allowCredentials = credential_ids.map((id) => ({
id: Uint8Array.from(
window
.atob(id.replace(/-/gmu, "+").replace(/_/gmu, "/"))
.split("")
.map((i) => i.charCodeAt())
),
type: "public-key",
alg: -7,
}));

const assertation = await window.navigator.credentials.get({
publicKey: {
userVerification: "required",
timeout: 6e4,
allowCredentials: credential_ids.map((id) => ({
id: Uint8Array.from(
window
.atob(id.replace(/-/gmu, "+").replace(/_/gmu, "/"))
.split("")
.map((i) => i.charCodeAt())
),
type: "public-key",
})),
allowCredentials,
challenge,
},
});
Expand Down
39 changes: 32 additions & 7 deletions internal/solve-y-coordinate-secp256r1.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
const b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604bn;
const a = 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffcn;
const p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffn;
const a = (-3n + p) % p;

function calculateYSquared(x) {
// Calculate y^2
const xCubed = x ** 3n % p;
const xCubed = (((x * x) % p) * x) % p;
const ax = (a * x) % p;
const ySquared = (xCubed + ax + b) % p;

Expand All @@ -18,13 +17,19 @@ function modPow(base, exponent, modulus) {
result = (result * base) % modulus;
}
base = (base * base) % modulus;
exponent = exponent / 2n;
exponent = exponent >> 1n;
}
return result;
}

function legendreSymbol(a, p) {
// If a is divisible by p, return 0
if (a % p === 0n) {
return 0;
}
// Compute the Legendre symbol using Euler's criterion
const symbol = modPow(a, (p - 1n) / 2n, p);
// If symbol is 1, it's a quadratic residue; if p-1, it's a non-residue
return symbol === 1n ? 1 : symbol === p - 1n ? -1 : 0;
}

Expand All @@ -37,17 +42,17 @@ function tonelliShanksAlgorithm(ySquared, p) {
let s = 0n;

while (q % 2n === 0n) {
q = q / 2n;
q = q >> 1n;
s += 1n;
}

let z = 2n;
while (modPow(z, (p - 1n) / 2n, p) !== p - 1n) {
while (modPow(z, (p - 1n) >> 1n, p) !== p - 1n) {
z += 1n;
}

let c = modPow(z, q, p);
let r = modPow(ySquared, (q + 1n) / 2n, p);
let r = modPow(ySquared, (q + 1n) >> 1n, p);
let t = modPow(ySquared, q, p);

let m = s;
Expand All @@ -70,6 +75,26 @@ function tonelliShanksAlgorithm(ySquared, p) {
return r;
}

export function caculateRecID(r) {
const ySquared = calculateYSquared(r);
const y = tonelliShanksAlgorithm(ySquared, p);
return Number(y % 2n);
}

export function calculateRecID(r) {
// Step 1: Calculate y^2 = r^3 - 3r + 7 mod p
const ySquared = calculateYSquared(r);

// Step 2: Check if y^2 is a quadratic residue modulo p
if (legendreSymbol(ySquared, p) === p - 1n) {
throw new Error("No valid y-coordinate found for r");
}
const y = tonelliShanksAlgorithm(ySquared, p);

const T = y > p / 2n ? p - y : y;
return Number(T % 2n);
}

export default function calculateY(x, prefix) {
const ySquared = calculateYSquared(x);
const y = tonelliShanksAlgorithm(ySquared, p);
Expand Down
19 changes: 4 additions & 15 deletions internal/webauthn_signature.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import varuint32 from "eosio-wasm-js/varuint32.mjs";
import ripemd160 from "ripemd160-js/ripemd160.mjs";

import decodeDER from "./decode-der.mjs";

const N =
115792089210356248762697446949407573529996955224135760342422259061068512044369n;
import { calculateRecID } from "./solve-y-coordinate-secp256r1.mjs";

export default async function webAuthSig({
authenticatorData,
Expand All @@ -18,28 +16,19 @@ export default async function webAuthSig({
r.reduce((acc, i) => (acc += i.toString("16").padStart(2, "0")), "0x")
);

const s_val = BigInt(
s.reduce((acc, i) => (acc += i.toString("16").padStart(2, "0")), "0x")
);

// Recid is bugged
// Need to recover the public key from the siganture to check the recid value
// also needs to be done on iskomorphic-secp256k1 to ensure stabilityk with signatures.

let recid = (r_val > N ? 2 : 0) | (s_val % 2n ? 1 : 0);
if (s_val < N / 2n) recid = recid ^ 1;
const recid = calculateRecID(r_val);

const sig = Uint8Array.from([
recid + 27 + 4,
...r,
...s,
...varuint32(authenticatorData.length ?? authenticatorData.byteLength)
.match(/[a-z0-9]{2}/gmu)
.map((i) => `0x${i}`),
.map((i) => Number(`0x${i}`)),
...new Uint8Array(authenticatorData),
...varuint32(clientDataJSON.length ?? clientDataJSON.byteLength)
.match(/[a-z0-9]{2}/gmu)
.map((i) => `0x${i}`),
.map((i) => Number(`0x${i}`)),
...new Uint8Array(clientDataJSON),
]);

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
},
"dependencies": {
"base58-js": "^2.0.0",
"elliptic": "^6.6.0",
"eosio-wasm-js": "^4.1.1",
"isomorphic-secp256k1-js": "^3.0.0",
"ripemd160-js": "^2.0.2",
Expand Down
14 changes: 0 additions & 14 deletions test/webauth_signature.test.mjs

This file was deleted.

0 comments on commit 64ab0e5

Please sign in to comment.