Skip to content

Commit

Permalink
Update for ledger-namada multisig changes (v0.22.0) (anoma#384)
Browse files Browse the repository at this point in the history
  • Loading branch information
jurevans authored Sep 13, 2023
1 parent 5b53a96 commit 2ccc40b
Show file tree
Hide file tree
Showing 15 changed files with 155 additions and 101 deletions.
14 changes: 6 additions & 8 deletions apps/extension/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,15 @@ export const generateId = (
* Convert ISignature into serialized and encoded signature
*/
export const encodeSignature = (sig: ISignature): Uint8Array => {
const { salt, indices, pubkey, signature } = sig;

// TODO: Note that the following "any" type usage below is a result of the buffer responses
// from the Ledger do not match the ISignature type! This will be fixed in a future release.
const { secIndices, singlesig, sigType, multisigIndices, multisig } = sig;

/* eslint-disable */
const props = {
salt: new Uint8Array((salt as any).data),
indices: new Uint8Array((indices as any).data),
pubkey: new Uint8Array((pubkey as any).data),
signature: new Uint8Array((signature as any).data),
secIndices: new Uint8Array((secIndices as any).data),
singlesig: singlesig ? new Uint8Array((singlesig as any).data) : undefined,
sigType,
multisigIndices: new Uint8Array((multisigIndices as any).data),
multisig: multisig.map((sig) => new Uint8Array((sig as any).data))
};
/* eslint-enable */

Expand Down
2 changes: 1 addition & 1 deletion packages/ledger-namada/dist/namadaApp.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import Transport from '@ledgerhq/hw-transport';
import { ResponseAddress, ResponseAppInfo, ResponseBase, ResponseSign, ResponseVersion } from './types';
import { LedgerError, SignatureType } from './common';
export { LedgerError };
export { LedgerError, SignatureType };
export * from './types';
export declare class NamadaApp {
transport: Transport;
Expand Down
2 changes: 1 addition & 1 deletion packages/ledger-namada/dist/namadaApp.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/ledger-namada/dist/namadaApp.js.map

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion packages/ledger-namada/dist/processResponses.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
* limitations under the License.
******************************************************************************* */
/// <reference types="node" />
import { SignatureType } from './common';
import { ISignature } from './types';
export declare function processGetSignatureResponse(response: Buffer): ISignature;
export declare function processGetSignatureResponse(signatureType: SignatureType, response: Buffer): ISignature;
export declare function processGetAddrResponse(response: Buffer): {
publicKey: Buffer;
address: Buffer;
Expand Down
63 changes: 43 additions & 20 deletions packages/ledger-namada/dist/processResponses.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/ledger-namada/dist/processResponses.js.map

Large diffs are not rendered by default.

20 changes: 11 additions & 9 deletions packages/ledger-namada/dist/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// <reference types="node" />
import { LedgerError } from './common';
import { LedgerError, SignatureType } from './common';
export interface ResponseBase {
errorMessage: string;
returnCode: LedgerError;
Expand Down Expand Up @@ -48,17 +48,19 @@ export interface ResponseNullifier extends ResponseBase {
}
export interface ISignature {
raw: Buffer;
salt: Buffer;
indices: Buffer;
pubkey: Buffer;
signature: Buffer | null;
secIndices: Buffer;
sigType: SignatureType;
singlesig: Buffer | null;
multisigIndices: Buffer;
multisig: Buffer[];
}
export declare class Signature implements ISignature {
raw: Buffer;
salt: Buffer;
indices: Buffer;
pubkey: Buffer;
signature: Buffer | null;
secIndices: Buffer;
sigType: SignatureType;
singlesig: Buffer | null;
multisigIndices: Buffer;
multisig: Buffer[];
isFilled: boolean;
constructor(signature?: ISignature);
}
Expand Down
20 changes: 11 additions & 9 deletions packages/ledger-namada/dist/types.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/ledger-namada/dist/types.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions packages/shared/lib/src/sdk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use namada::{
signing,
wallet::{Store, Wallet},
},
proto::{Section, Tx},
proto::Tx,
types::key::common::PublicKey,
};
use wasm_bindgen::{prelude::wasm_bindgen, JsError, JsValue};
Expand Down Expand Up @@ -290,11 +290,11 @@ impl Sdk {
) -> Result<Tx, JsError> {
let mut tx: Tx = Tx::try_from_slice(tx_bytes)?;

let raw_sig = signature::construct_signature(raw_sig_bytes, &tx)?;
tx.add_section(Section::Signature(raw_sig));
let raw_sig_section = signature::construct_signature(raw_sig_bytes, &tx)?;
tx.add_section(raw_sig_section);

let wrapper_sig = signature::construct_signature(wrapper_sig_bytes, &tx)?;
tx.add_section(Section::Signature(wrapper_sig));
let wrapper_sig_section = signature::construct_signature(wrapper_sig_bytes, &tx)?;
tx.add_section(wrapper_sig_section);

tx.protocol_filter();

Expand Down
87 changes: 54 additions & 33 deletions packages/shared/lib/src/sdk/signature.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
use borsh::{BorshDeserialize, BorshSerialize};
use namada::proto::{Signature, Tx};
use namada::proto::{MultiSignature, Section, Signature, Tx};
use wasm_bindgen::JsError;

#[derive(Copy, Clone, Debug, BorshSerialize, BorshDeserialize)]
pub enum SignatureType {
Raw = 0,
Wrapper = 1,
}

#[derive(BorshSerialize, BorshDeserialize)]
pub struct SignatureMsg {
salt: Vec<u8>,
indices: Vec<u8>,
pubkey: Vec<u8>,
signature: Vec<u8>,
sec_indices: Vec<u8>,
singlesig: Option<Vec<u8>>,
sig_type: SignatureType,
multisig_indices: Vec<u8>,
multisig: Vec<Vec<u8>>,
}

/// Reconstructs a proto::Signature using the provided indices to retrieve hashes from Tx
Expand All @@ -21,43 +28,57 @@ pub struct SignatureMsg {
///
/// Returns JsError if the sig_msg can't be deserialized or
/// Rust structs can't be created.
pub fn construct_signature(sig_msg: &[u8], tx: &Tx) -> Result<Signature, JsError> {
let sig_msg = SignatureMsg::try_from_slice(sig_msg)?;

pub fn construct_signature(sig_msg: &[u8], tx: &Tx) -> Result<Section, JsError> {
let SignatureMsg {
salt,
indices,
pubkey,
signature,
} = sig_msg;
sec_indices,
singlesig,
sig_type,
multisig_indices,
multisig,
} = SignatureMsg::try_from_slice(sig_msg)?;

// Signature section bytes start with salt
let mut sig = salt;
let mut public_key = pubkey;
let mut signature = signature;

// Which is followed the number of sections
let mut indices_length = vec![indices.len() as u8, 0, 0, 0];
sig.append(&mut indices_length);
// Start with the number of section indices with a pad
let indices = vec![sec_indices.len() as u8, 0, 0, 0];
let mut sig = indices;

// Which is followed by the hash of each section in the order specified
for i in 0..indices.len() {
let sechash = match indices[i] {
for i in 0..sec_indices.len() {
let sechash = match sec_indices[i] {
0 => tx.header_hash(),
_ => tx.sections[indices[i] as usize - 1].get_hash(),
_ => tx.sections[sec_indices[i] as usize - 1].get_hash(),
};

sig.append(&mut sechash.to_vec());
sig.extend_from_slice(&sechash.to_vec());
}

// Which is followed by the public key of the signer
sig.append(&mut public_key);

// Indicates that a signature follows
sig.append(&mut vec![0x01]);
match sig_type {
SignatureType::Wrapper => {
// Indicates that a signature follows
sig.extend_from_slice(&vec![0x01]);

// Followed by the signature
sig.append(&mut signature);
// Followed by the signature
match singlesig {
Some(v) => {
sig.extend_from_slice(&v);
}
// This shouldn't happen:
None => panic!("singlesig is required for SignatureType::Wrapper"),
}
Ok(Section::Signature(Signature::try_from_slice(&sig)?))
}
SignatureType::Raw => {
// Multisigs start with the number of signatures
sig.extend_from_slice(&vec![multisig_indices.len() as u8, 0, 0, 0]);
// Followed by a sequence of signature - index pairs
for (signature, idx) in multisig.iter().zip(multisig_indices) {
// Add the bytes of the signature
sig.extend_from_slice(&signature);
// Add a byte representing the index of the signature
sig.push(idx);
}
let multisignature = MultiSignature::try_from_slice(&sig)?;

Ok(Signature::try_from_slice(&sig)?)
Ok(Section::SectionSignature(multisignature))
}
}
}
1 change: 1 addition & 0 deletions packages/types/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"lint:ci": "yarn lint --max-warnings 0"
},
"dependencies": {
"@namada/ledger-namada": "0.0.1",
"bn.js": "^5.2.1",
"@dao-xyz/borsh": "^5.1.5",
"slip44": "^2.0.4",
Expand Down
18 changes: 11 additions & 7 deletions packages/types/src/tx/schema/signature.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { field, vec } from "@dao-xyz/borsh";
import { field, option, vec } from "@dao-xyz/borsh";
import { SignatureType } from "@namada/ledger-namada";
import { SignatureProps } from "../types";

export class SignatureMsgValue {
@field({ type: vec("u8") })
salt!: Uint8Array;
secIndices!: Uint8Array;

@field({ type: vec("u8") })
indices!: Uint8Array;
@field({ type: option(vec("u8")) })
singlesig!: Uint8Array;

@field({ type: vec("u8") })
pubkey!: Uint8Array;
@field({ type: "u8" })
sigType!: SignatureType;

@field({ type: vec("u8") })
signature!: Uint8Array;
multisigIndices!: Uint8Array;

@field({ type: vec(vec("u8")) })
multisig!: Uint8Array[];

constructor(data: SignatureProps) {
Object.assign(this, data);
Expand Down
Loading

0 comments on commit 2ccc40b

Please sign in to comment.