Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using nns-dapp and quill with the same seed will generate different principal_id #863

Open
YellowOpenSource opened this issue May 18, 2022 · 0 comments

Comments

@YellowOpenSource
Copy link

YellowOpenSource commented May 18, 2022

The principal_id generated locally through the seed is inconsistent with the principal_id displayed on the nns dapp:

Take the following two pieces of code as an example:

seed:1947400 story goddess birth execute canoe sense poverty orchard feel mule indoor credit bulb arrest primary giggle turtle order tell glimpse grid act motion february

nns generated: jwfy3-6d6bo-ri5le-apblk-7tmrd-h7sj5-srhi4-4wntx-4daz6-missz-yqe
local generated: nrw4v-2qe5h-dor7z-mm7x4-hfa5f-tfls6-avaja-aysww-c6bwg-g25mq-jqe

local code
import { Ed25519KeyIdentity } from '@dfinity/identity';
import { mnemonicToSeedSync } from "bip39";
import {
    pub_key_to_address,
} from '@dfinity/rosetta-client';
let crypto;

const HARDENED = 0x80000000;

function toBigEndianArray(n) {
    const byteArray = new Uint8Array([0, 0, 0, 0]);
    for (let i = byteArray.length - 1; i >= 0; i--) {
        const byte = n & 0xff;
        byteArray[i] = byte;
        n = (n - byte) / 256;
    }
    return byteArray;
}

async function derive(
    parentKey,
    parentChaincode,
    i,
) {
    // From the spec: Data = 0x00 || ser256(kpar) || ser32(i)
    const data = new Uint8Array([0, ...parentKey, ...toBigEndianArray(i)]);
    const key = await crypto.subtle.importKey(
        'raw',
        parentChaincode,
        {
            name: 'HMAC',
            hash: { name: 'SHA-512' },
        },
        false,
        ['sign'],
    );

    const h = await crypto.subtle.sign('HMAC', key, data.buffer);
    const slipSeed = new Uint8Array(h.slice(0, 32));
    const chainCode = new Uint8Array(h.slice(32));
    return [slipSeed, chainCode];
}

async function generateMasterKey(
    seed,
) {
    const data = new TextEncoder().encode('ed25519 seed');
    const key = await crypto.subtle.importKey(
        'raw',
        data,
        {
            name: 'HMAC',
            hash: { name: 'SHA-512' },
        },
        false,
        ['sign'],
    );
    const h = await crypto.subtle.sign('HMAC', key, seed);
    const slipSeed = new Uint8Array(h.slice(0, 32));
    const chainCode = new Uint8Array(h.slice(32));
    return [slipSeed, chainCode];
}

export async function fromSeedWithSlip0010(
    masterSeed,
    derivationPath,
) {
    let [slipSeed, chainCode] = await generateMasterKey(masterSeed);

    for (let i = 0; i < derivationPath.length; i++) {
        [slipSeed, chainCode] = await derive(
            slipSeed,
            chainCode,
            derivationPath[i] | HARDENED,
        );
    }

    return Ed25519KeyIdentity.generate(slipSeed);
}

async function main() {
    try {
        crypto = await import('node:crypto');
    } catch (err) {
        console.log('crypto support is disabled!');
    }
    crypto.subtle
    const mem = "story goddess birth execute canoe sense poverty orchard feel mule indoor credit bulb arrest primary giggle turtle order tell glimpse grid act motion february"
    const seed = mnemonicToSeedSync(mem);
    const id = await fromSeedWithSlip0010(seed, [44, 223, 0, 0, 0]);
    console.log(id.getPublicKey().toDer())
    // console.log(pub_key_to_address(id.getPublicKey()))
}

main()
nns-dapp code
import { Ed25519KeyIdentity } from '@dfinity/identity';
import { mnemonicToSeedSync } from "bip39";
let crypto;

const HARDENED = 0x80000000;

function toBigEndianArray(n) {
    const byteArray = new Uint8Array([0, 0, 0, 0]);
    for (let i = byteArray.length - 1; i >= 0; i--) {
        const byte = n & 0xff;
        byteArray[i] = byte;
        n = (n - byte) / 256;
    }
    return byteArray;
}

async function derive(
    parentKey,
    parentChaincode,
    i,
) {
    // From the spec: Data = 0x00 || ser256(kpar) || ser32(i)
    const data = new Uint8Array([0, ...parentKey, ...toBigEndianArray(i)]);
    const key = await crypto.subtle.importKey(
        'raw',
        parentChaincode,
        {
            name: 'HMAC',
            hash: { name: 'SHA-512' },
        },
        false,
        ['sign'],
    );

    const h = await crypto.subtle.sign('HMAC', key, data.buffer);
    const slipSeed = new Uint8Array(h.slice(0, 32));
    const chainCode = new Uint8Array(h.slice(32));
    return [slipSeed, chainCode];
}

async function generateMasterKey(
    seed,
) {
    const data = new TextEncoder().encode('ed25519 seed');
    const key = await crypto.subtle.importKey(
        'raw',
        data,
        {
            name: 'HMAC',
            hash: { name: 'SHA-512' },
        },
        false,
        ['sign'],
    );
    const h = await crypto.subtle.sign('HMAC', key, seed);
    const slipSeed = new Uint8Array(h.slice(0, 32));
    const chainCode = new Uint8Array(h.slice(32));
    return [slipSeed, chainCode];
}

export async function fromSeedWithSlip0010(
    masterSeed,
    derivationPath,
) {
    let [slipSeed, chainCode] = await generateMasterKey(masterSeed);

    for (let i = 0; i < derivationPath.length; i++) {
        [slipSeed, chainCode] = await derive(
            slipSeed,
            chainCode,
            derivationPath[i] | HARDENED,
        );
    }

    return Ed25519KeyIdentity.generate(slipSeed);
}

async function main() {
    try {
        crypto = await import('node:crypto');
    } catch (err) {
        console.log('crypto support is disabled!');
    }
    crypto.subtle
    const mem = "story goddess birth execute canoe sense poverty orchard feel mule indoor credit bulb arrest primary giggle turtle order tell glimpse grid act motion february"
    const seed = mnemonicToSeedSync(mem);
    const id = await fromSeedWithSlip0010(seed, [44, 223, 0, 0, 0]);
    console.log(id.getPrincipal().toString())
}

main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants
@YellowOpenSource and others