Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@bicycle-codes/ailuropoda

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bicycle-codes/ailuropoda

Bamboo implemented in typescript

  • 0.0.7
  • latest
  • Source
  • npm
  • Socket score

Version published
Maintainers
1
Created
Source

ailuropoda

tests types module semantic versioning license

Implementing bamboo, using only browser compatible cryptography.

Ailuropoda is the science name for a panda.

install

npm i -S @bicycle-codes/ailuropoda

use

Import types and functions.

import {
    create as createMsg,
    SignedPost,
    lipmaaLink,
    createBatch,
    getLipmaaPath,
    isValid,
    verifyLipmaas
} from '@bicycle-codes/ailuropoda'

data format

Log entries are { metadata, content }, where metadata is a signed object like below.

Metadata

interface Metadata {
    timestamp:number;
    proof:string,
    key:string,  // <-- base64url encoded
    seq:number;
    lipmaalink:string|null;
    prev:string|null;
    username:string;
    author:DID;
}

SignedMetadata

import { SignedMessage } from '@bicycle-codes/message'

type SignedMetadata = SignedMessage<Metadata>

Content

export interface Content {
    text:string,
    alt?:string[],
    mentions?:string[]
}

SignedPost

type SignedPost = { metadata:SignedMetadata, content:Content }

example

Use the function createBatch to create a list with lipmaa links.

See the diagram for a nice visualization of the list structure.

import { Identity, create as createID } from '@bicycle-codes/identity'
import { createCryptoComponent } from '@ssc-half-light/node-components'
import { createBatch } from '@bicycle-codes/ailuropoda'

const alicesCrytpo = await createCryptoComponent()
const alice = await createID(alicesCrytpo, {
    humanName: 'alice',
    humanReadableDeviceName: 'computer'
})

const newMsgs = [
    { content: { text: 'hello 1' } },
    { content: { text: 'hello 2' } },
    { content: { text: 'hello 3' } },
    { content: { text: 'hello 4' } },
    { content: { text: 'hello 5' } }
]

const list = await createBatch(alice, alicesCrytpo, {
    // we are just using an in-memory array of messages
    getKeyFromIndex: async (i:number, msgs:SignedPost[]) => {
        const msg = msgs[i]
        if (!msg) return null
        return msg.metadata.key
    }
}, newMsgs)  // pass in a list with message content

API

Get the lipmaa number number given a sequence number.

function lipmaaLink (n:number):number
const lipmaas = ([...Array(41).keys()]).map(n => {
    return { lipmaa: lipmaaLink(n), n }
})

lipmaas is like this:

 [
    { lipmaa: 0, n: 0 },   { lipmaa: 0, n: 1 },
    { lipmaa: 1, n: 2 },   { lipmaa: 2, n: 3 },
    { lipmaa: 1, n: 4 },   { lipmaa: 4, n: 5 },
    { lipmaa: 5, n: 6 },   { lipmaa: 6, n: 7 },
    { lipmaa: 4, n: 8 },   { lipmaa: 8, n: 9 },
    { lipmaa: 9, n: 10 },  { lipmaa: 10, n: 11 },
    { lipmaa: 8, n: 12 },  { lipmaa: 4, n: 13 },
    { lipmaa: 13, n: 14 }, { lipmaa: 14, n: 15 },
    { lipmaa: 15, n: 16 }, { lipmaa: 13, n: 17 },
    { lipmaa: 17, n: 18 }, { lipmaa: 18, n: 19 },
    { lipmaa: 19, n: 20 }, { lipmaa: 17, n: 21 },
    { lipmaa: 21, n: 22 }, { lipmaa: 22, n: 23 },
    { lipmaa: 23, n: 24 }, { lipmaa: 21, n: 25 },
    { lipmaa: 13, n: 26 }, { lipmaa: 26, n: 27 },
    { lipmaa: 27, n: 28 }, { lipmaa: 28, n: 29 },
    { lipmaa: 26, n: 30 }, { lipmaa: 30, n: 31 },
    { lipmaa: 31, n: 32 }, { lipmaa: 32, n: 33 },
    { lipmaa: 30, n: 34 }, { lipmaa: 34, n: 35 },
    { lipmaa: 35, n: 36 }, { lipmaa: 36, n: 37 },
    { lipmaa: 34, n: 38 }, { lipmaa: 26, n: 39 },
    { lipmaa: 13, n: 40 }
]

Note the lipmaa vs n properties match with this diagram.

lipmaa diagram

create (user, crypto, opts)

Create a message. This does not deal with lipmaa links. You would need to pass them in.

async function create (
    user:Identity,
    crypto:Implementation,
    opts:{
        content:Content,
        limpaalink?:string|null,  // <-- the key of the lipmaa message
        seq:number,
        prev:SignedPost|null|undefined,
    }
):Promise<SignedPost>
import { create as createMsg } from '@bicycle-codes/ailuropoda'

const post = await createMsg(
    alice,
    alicesCrytpo,
    {
        seq: 1,
        prev: null,
        content: {
            text: 'hello'
        }
    }
)

isValid (message)

Verify a message. This does not look at links, only the signature and hash.

async function isValid (msg:SignedPost):Promise<boolean>
const { isOk } = await isValid(post)
// => true

verifyLipmaas ({ messageFromKey }, msg, path)

Check that all the messages between the given message and message number 1 are valid. This will use the shortest path from the given message to the first message.

async function verifyLipmaas ({
    messageFromKey
}:{
    messageFromKey:(key:string)=>Promise<SignedPost>
}, msg:SignedPost, path?:number[]):Promise<{
    isOk: boolean,
    path:number[]
}>
const { isOk, path } = await verifyLipmaas(list2, {
    messageFromKey
}, list2[39])  // array is 0 indexed, so 39 is seq number 40

// isOk = true
// path = [40, 13, 4, 1]

getLipmaaPath (seq, prev)

Get the shortest path between the given sequence number and the first message. The parameter prev is used internally, for recusion.

function getLipmaaPath (seq:number, prev?:number[]):number[]

Return an array of sequence numbers, starting with the first:

[ 1, 4, 13 ]

createBatch (user, crypto, opts, messages)

Create a linked list of the given messages, with lipmaa links.

async function createBatch (
    user:Identity,
    crypto:Implementation,
    opts: {
        getKeyFromIndex:(i:number, msgs:SignedPost[]) => Promise<string|null>
    },
    msgs:{
        content:Content,
        seq?:number,
        prev?:SignedPost|null|undefined,
    }[],
    _out?:SignedPost[]
):Promise<SignedPost[]>
createBatch example

Create a linked list with in-memory content, starting from entry number 1.

Note in the example, getKey is synchronous, but we need to return a promise because that's what the API expects.

Takes a parameter getKeyFromIndex that will return the key for an entry given its index.

const newMsgs = [
    { content: { text: 'hello 1' } },
    { content: { text: 'hello 2' } },
    { content: { text: 'hello 3' } },
    { content: { text: 'hello 4' } },
    { content: { text: 'hello 5' } }
]

const list = await createBatch(alice, alicesCrytpo, {
    getKeyFromIndex: getKey
}, newMsgs)

async function getKey (i:number, msgs:SignedPost[]):Promise<string|null> {
    const msg = msgs[i]
    if (!msg) return null
    return msg.metadata.key
}

append (user, crypto, opts)

Given a previous message and a function that will return a message by its sequence number, create a new message with the correct lipmaa key.

async function append (
    user:Identity,
    crypto:Implementation,
    opts:{
        getBySeq:(seq:number) => Promise<SignedPost>
        content:Content,
        prev:SignedPost
    }
):Promise<SignedPost>
append example
const list = await createBatch(alice, alicesCrytpo, {
    getKeyFromIndex: async (i, msgs) => {
        return msgs[i].metadata.key
    },
}, msgs)

const newMsg = await append(alice, alicesCrytpo, {
    getBySeq: async (seq) => {
        return list[seq - 1]  // 0 vs 1 indexed
    },
    prev: list[list.length - 1],
    content: { text: 'hello 40' }
})

docs

Generated via typescript.

bicycle-codes.github.io/ailuropoda

Keywords

FAQs

Package last updated on 01 May 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc