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

feat: varsig #186

Open
wants to merge 114 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
114 commits
Select commit Hold shift + click to select a range
64c1398
varsig dummy pkg
ukstv Nov 20, 2023
94074da
bytes
ukstv Nov 20, 2023
d8ac024
dummy sig
ukstv Nov 20, 2023
b7ae759
varsig
ukstv Nov 20, 2023
ce26395
wip
ukstv Nov 20, 2023
77db8b1
wip
ukstv Nov 20, 2023
958fba6
wip
ukstv Nov 20, 2023
1353303
Sketch for api interface using eip712
oed Nov 20, 2023
3052e92
fix eip712 encoder
oed Nov 20, 2023
3591453
eip712 more compression
oed Nov 20, 2023
c2756ad
eip712 fixes
oed Nov 20, 2023
979f230
wip
ukstv Nov 21, 2023
9800f29
Full eip712 impl
oed Nov 21, 2023
d7c53fd
wip
ukstv Nov 21, 2023
27fcc10
it builds
ukstv Nov 21, 2023
404f97a
less stuff
ukstv Nov 21, 2023
7e36eb4
fancy
ukstv Nov 21, 2023
cba36a1
fancy
ukstv Nov 21, 2023
a61c677
fancy
ukstv Nov 21, 2023
4dffe85
fancy
ukstv Nov 21, 2023
004b0d1
fancy
ukstv Nov 21, 2023
5861a6b
fancy
ukstv Nov 21, 2023
4ae4302
fancy
ukstv Nov 21, 2023
1642e84
fancy
ukstv Nov 21, 2023
82a97c6
fancy
ukstv Nov 21, 2023
9e54144
wip
ukstv Nov 21, 2023
04a30a5
wip
ukstv Nov 21, 2023
8a5677e
bytes-tape
ukstv Nov 21, 2023
43685a0
wip
ukstv Nov 21, 2023
105d14d
wip
ukstv Nov 21, 2023
2de394b
hashing algo
ukstv Nov 21, 2023
2326b08
drop unused code
ukstv Nov 21, 2023
1fb82f4
Encode signatures eip712
oed Nov 21, 2023
40201a4
wip
ukstv Nov 23, 2023
53560ac
wip
ukstv Nov 23, 2023
e1ec689
712
ukstv Nov 23, 2023
d07e77a
Merge remote-tracking branch 'origin/feat/varsig' into feat/varsig
ukstv Nov 23, 2023
f7a56e4
make it work
ukstv Nov 23, 2023
77f1e04
make it work
ukstv Nov 23, 2023
03c0482
wip
ukstv Nov 23, 2023
198e9c2
wip
ukstv Nov 23, 2023
cbf2fc7
wip
ukstv Nov 23, 2023
270324a
remove unused varsig.ts experiment
ukstv Nov 23, 2023
c72d310
remove unused varbytes.ts experiment
ukstv Nov 23, 2023
c70d877
signing test
ukstv Nov 23, 2023
3fd4ceb
hashing test
ukstv Nov 23, 2023
11502a2
wip
ukstv Nov 23, 2023
b3a813b
wip
ukstv Nov 23, 2023
059db6e
Add test vectors for eip712
oed Nov 23, 2023
a838a73
A bunch of stuff
oed Nov 23, 2023
e7e27a9
wip 0xe712
ukstv Nov 23, 2023
9b18fb5
Main entrypoint
oed Nov 23, 2023
765e5e3
test 712 can
ukstv Nov 23, 2023
e62f9f8
decoder
ukstv Nov 23, 2023
d70d648
Merge remote-tracking branch 'origin/feat/varsig' into feat/varsig
ukstv Nov 23, 2023
c94fdaf
decoder
ukstv Nov 23, 2023
cc1008b
cleanup
ukstv Nov 23, 2023
1e7eb1c
cleanup
ukstv Nov 23, 2023
04ade47
cleanup
ukstv Nov 23, 2023
97a6cd1
Top level API
oed Nov 23, 2023
f9266b5
Full flow almost
oed Nov 23, 2023
0e8ddd3
Implement signature verifier
oed Nov 23, 2023
6219181
Make more test pass
oed Nov 23, 2023
ab58598
wip
ukstv Nov 23, 2023
6712aea
Merge remote-tracking branch 'origin/feat/varsig' into feat/varsig
ukstv Nov 23, 2023
4682c26
wip
ukstv Nov 23, 2023
512c91b
Fix secp tests
oed Nov 23, 2023
8305031
Fix more tests
oed Nov 23, 2023
755f741
Clean up singning
oed Nov 23, 2023
af1a4a2
Add way to recover original
oed Nov 23, 2023
0105edb
types
ukstv Nov 23, 2023
186daca
types
ukstv Nov 23, 2023
42c2e60
right types
ukstv Nov 23, 2023
cb66ae4
wip
ukstv Nov 23, 2023
6c34c5c
builds
ukstv Nov 24, 2023
0d225b9
decompression
ukstv Nov 24, 2023
8732927
decompression
ukstv Nov 24, 2023
000cf85
decompression
ukstv Nov 24, 2023
baedcdb
Move tests
oed Nov 24, 2023
18173a5
types
ukstv Nov 24, 2023
4449703
Lint
oed Nov 24, 2023
4d51cdb
wip
ukstv Nov 24, 2023
23200a9
eip712 test ok
ukstv Nov 24, 2023
5801310
gen-vectors 2
ukstv Nov 24, 2023
64c8fed
Full api
oed Nov 24, 2023
158ad76
wip
ukstv Nov 24, 2023
c2b3f53
npm run gen:vectors
ukstv Nov 24, 2023
ea27266
gen-vector!
ukstv Nov 24, 2023
626cf7d
recoverybit
ukstv Nov 24, 2023
8fd01d6
JWS canon
oed Nov 24, 2023
002bb52
Add magic
oed Nov 24, 2023
ec55e18
Fix magic
oed Nov 24, 2023
3c45f19
tooriginal
ukstv Nov 24, 2023
fecde32
fix
ukstv Nov 24, 2023
cb642f5
change files
ukstv Nov 24, 2023
ee57f90
Broke the tests
oed Nov 24, 2023
a68834b
does it build?
oed Nov 24, 2023
49ee4f1
cleanup
oed Nov 24, 2023
5e82951
half test
oed Nov 24, 2023
e8adc9e
skipped a bunch of old tests
oed Nov 24, 2023
259f9cf
tests and builds
ukstv Nov 24, 2023
329437b
pacify linter
ukstv Nov 24, 2023
6a60f69
pacify linter pt2
ukstv Nov 24, 2023
6bcd606
pacify linter pt2
ukstv Nov 24, 2023
0331872
JWS test vectors just dropped
oed Nov 25, 2023
efb66ec
Merge branch 'main' into feat/varsig
oed Jan 6, 2024
7c9534e
JWS Canon test
oed Jan 10, 2024
f9d7f08
JWS work
oed Feb 6, 2024
074fe31
Implement hashing
oed Feb 6, 2024
96c9271
Fix jws canonicalization + old tests
oed Feb 8, 2024
f5ffa20
JWS works for p256 and secpk1
oed Feb 8, 2024
bd0978e
Most things are working
oed Feb 8, 2024
f4911bb
All varsig tests passing
oed Feb 8, 2024
d9b24b0
eslint, plz don't mind my test
oed Feb 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# http://editorconfig.org

root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false
4 changes: 4 additions & 0 deletions packages/varsig/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.log
.DS_Store
node_modules
dist
5 changes: 5 additions & 0 deletions packages/varsig/LICENSE-APACHE
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
19 changes: 19 additions & 0 deletions packages/varsig/LICENSE-MIT
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
The MIT License (MIT)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
42 changes: 42 additions & 0 deletions packages/varsig/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Multidid
Multidid is a representation strategy for DIDs and DID URLs that is very compact and extensible. It allows any DID method to be represented as a string of bytes. Reference [specification](https://github.com/ChainAgnostic/multidid).

This library is a multidid utility library to encode and decode multidids to their byte and string representation and convert from did strings to multidid representations.

## Installation

```
npm install --save @didtools/multidid
```

## Usage

```js
import { Multidid } from '@didtools/multidid'

const didString = "did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp#z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp"

// Multidid instance from did string
const multidid = Multidid.fromString(didString)

// Encode to bytes
multidid.toBytes()

// Decode from bytes to multidid instance
Multidid.fromBytes(bytes)

// Encode as a multibase base16 string
const mdStr = multidid.toMultibase('base16')
console.log(mdStr)
//f9d1aed013b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29307a364d6b6954427a31796d75657041513448454859534631483871754735474c5656515233646a6458336d446f6f5770

// Multidid instance from base encoded string
Multidid.fromMultibase(mdStr)

// DID string from multidid
multidid.toString()
```

## License

Apache-2.0 OR MIT
22 changes: 22 additions & 0 deletions packages/varsig/jest.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"moduleFileExtensions": ["js", "json", "ts"],
"testRegex": ".(spec|test).ts$",
"testEnvironment": "node",
"extensionsToTreatAsEsm": [".ts"],
"globals": {
"ts-jest": {
"useESM": true
}
},
"moduleNameMapper": {
"^(\\.{1,2}/.*)\\.js$": "$1"
},
"transform": {
"^.+\\.(t|j)s$": [
"@swc/jest",
{
"root": "../.."
}
]
}
}
68 changes: 68 additions & 0 deletions packages/varsig/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"name": "@didtools/varsig",
"version": "0.0.1",
"author": "3Box Labs",
"license": "(Apache-2.0 OR MIT)",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": "./dist/index.js"
},
"files": [
"dist"
],
"engines": {
"node": ">=14.14"
},
"sideEffects": false,
"scripts": {
"build:clean": "del dist",
"build:js": "swc src -d ./dist --config-file ../../.swcrc",
"build:types": "tsc --emitDeclarationOnly --skipLibCheck",
"build": "pnpm run build:clean && pnpm run build:types && pnpm run build:js",
"lint": "eslint src --fix",
"test": "node --experimental-vm-modules ../../node_modules/jest/bin/jest.js",
"test:ci": "pnpm run test --ci --coverage",
"prepare": "pnpm run build",
"prepublishOnly": "package-check",
"size": "./node_modules/.bin/size-limit",
"analyze": "./node_modules/.bin/size-limit --why",
"gen:vectors": "./node_modules/.bin/tsm ./src/__tests__/gen-vectors.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ceramicnetwork/js-did.git"
},
"keywords": [
"DID",
"identity",
"did-provider",
"self-sovereign",
"multiformat"
],
"bugs": {
"url": "https://github.com/ceramicnetwork/js-did/issues"
},
"homepage": "https://github.com/ceramicnetwork/js-did#readme",
"devDependencies": {
"@stablelib/random": "^1.0.2",
"cartonne": "^3.0.1",
"tsm": "^2.3.0"
},
"dependencies": {
"@ipld/dag-json": "^10.1.5",
"@noble/curves": "^1.2.0",
"@noble/hashes": "^1.3.2",
"@types/node": "^20.2.3",
"codeco": "^1.1.0",
"fast-json-stable-stringify": "^2.1.0",
"key-did-provider-ed25519": "workspace:^",
"key-did-resolver": "workspace:^",
"klona": "^2.0.6",
"multiformats": "^13.0.1",
"uint8arrays": "^5.0.2",
"varintes": "^2.0.5",
"viem": "^1.19.5"
}
}
Binary file not shown.
Binary file added packages/varsig/src/__tests__/__vectors__/jws.car
Binary file not shown.
118 changes: 118 additions & 0 deletions packages/varsig/src/__tests__/canonicalization.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { expect, test } from '@jest/globals'
import { BytesTape } from '../bytes-tape.js'
import { CanonicalizationDecoder, CanonicalizationKind } from '../canonicalization.js'
import { concat, toString } from 'uint8arrays'
import { encode } from 'varintes/encode'
import { HashingKind, hashingAlgoByKind } from '../hashing.js'
import { SigningKind } from '../signing.js'
import { fromOriginal } from '../canons/eip712.js'

const TEST_DATA = {
types: {
EIP712Domain: [
{
name: 'name',
type: 'string',
},
{
name: 'version',
type: 'string',
},
{
name: 'chainId',
type: 'uint256',
},
{
name: 'verifyingContract',
type: 'address',
},
],
Person: [
{
name: 'name',
type: 'string',
},
{
name: 'wallet',
type: 'address',
},
],
Mail: [
{
name: 'from',
type: 'Person',
},
{
name: 'to',
type: 'Person',
},
{
name: 'contents',
type: 'string',
},
{
name: 'attachment',
type: 'bytes',
},
],
},
primaryType: 'Mail',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
attachment: '0xababababababababababa83459873459873459873498575986734359',
},
signature:
'0x0c095239e4d3d2cc0b7aa28110f42abcdefe47656bbde7048244471e701331ec3f94adfe7959b0ed0efec533d511f9e1e11b3e47242d82341870dc31fbc2146d1b',
} as const

test('EIP712', () => {
const node = fromOriginal({
// @ts-ignore
types: TEST_DATA.types,
domain: TEST_DATA.domain,
primaryType: TEST_DATA.primaryType,
message: TEST_DATA.message,
signature: TEST_DATA.signature,
})
const tape = new BytesTape(node._sig)
tape.readVarint() // skip varsig sigil
tape.readVarint() // skip key sigil
tape.read(1)
tape.readVarint() // skip hash sigil
const canonicalization = CanonicalizationDecoder.read(
tape,
hashingAlgoByKind(HashingKind.KECCAK256),
SigningKind.SECP256K1,
)
expect(canonicalization.kind).toEqual(CanonicalizationKind.EIP712)
if (canonicalization.kind !== CanonicalizationKind.EIP712) throw new Error()
const input = toString(canonicalization(TEST_DATA.message), 'hex')
expect(input).toEqual('703012a88c79c0ae106c7e0bd144d39d63304df1815e6d11b19189aff3dce0c4')
})

test('EIP191', () => {
const bytes = concat([encode(0xe191)[0]])
const tape = new BytesTape(bytes)
const result = CanonicalizationDecoder.read(
tape,
hashingAlgoByKind(HashingKind.KECCAK256),
SigningKind.SECP256K1,
)
expect(result.kind).toEqual(CanonicalizationKind.EIP191)
const canonicalized = toString(result('Hello'), 'hex')
expect(canonicalized).toEqual('aa744ba2ca576ec62ca0045eca00ad3917fdf7ffa34fbbae50828a5a69c1580e')
})
78 changes: 78 additions & 0 deletions packages/varsig/src/__tests__/canons/eip712.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { fromOriginal, prepareCanonicalization } from '../../canons/eip712.js'
import { BytesTape } from '../../bytes-tape.js'
import * as uint8arrays from 'uint8arrays'
import { HashingDecoder } from '../../hashing.js'
import { CanonicalizationKind } from '../../canonicalization.js'

const testData = {
types: {
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' },
],
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
{ name: 'attachment', type: 'bytes' },
],
},
primaryType: 'Mail',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
attachment: '0xababababababababababa83459873459873459873498575986734359',
},
signature:
'0x0c095239e4d3d2cc0b7aa28110f42abcdefe47656bbde7048244471e701331ec3f94adfe7959b0ed0efec533d511f9e1e11b3e47242d82341870dc31fbc2146d1b',
} as const

const expectedHash = uint8arrays.fromString(
'703012a88c79c0ae106c7e0bd144d39d63304df1815e6d11b19189aff3dce0c4',
'base16',
)

test('Encode eip712 message', () => {
// @ts-ignore
const node = fromOriginal(testData)

expect(node._sig.length).toEqual(268)
expect(node.attachment instanceof Uint8Array).toBeTruthy()
})

test('Canonicalize ipld eip712 object', () => {
// @ts-ignore
const node = fromOriginal(testData)
const tape = new BytesTape(node._sig)
tape.readVarint() // skip sigil
tape.readVarint() // skip key type
tape.read(1) // skip recovery bit
const hashing = HashingDecoder.read(tape) // read hash type
tape.readVarint() // skip canonicalizer codec
const can = prepareCanonicalization(tape, hashing, 0xe7)
if (can.kind !== CanonicalizationKind.EIP712) throw new Error(`Nope`)
expect(tape.remainder.length).toEqual(64)
// @ts-ignore
delete node._sig
const sigInput = can(node)
expect(sigInput).toEqual(expectedHash)
})
Loading
Loading