Skip to content

Commit

Permalink
fix: P-654 added solana signature check (#2635)
Browse files Browse the repository at this point in the history
Co-authored-by: higherordertech <higherordertech>
  • Loading branch information
higherordertech committed Apr 11, 2024
1 parent 4333ad6 commit d3e0f30
Show file tree
Hide file tree
Showing 11 changed files with 796 additions and 11 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,7 @@ jobs:
- test_name: lit-di-substrate-identity-test
- test_name: lit-di-evm-identity-test
- test_name: lit-di-bitcoin-identity-test
- test_name: lit-di-solana-identity-test
- test_name: lit-di-vc-test
- test_name: lit-dr-vc-test
- test_name: lit-parentchain-nonce
Expand Down
28 changes: 28 additions & 0 deletions bitacross-worker/litentry/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ impl LitentryMultiSignature {
|| self.verify_substrate(msg, address),
Identity::Evm(address) => self.verify_evm(msg, address),
Identity::Bitcoin(address) => self.verify_bitcoin(msg, address),
Identity::Solana(address) => self.verify_solana(msg, address),
_ => false,
}
}
Expand Down Expand Up @@ -155,6 +156,17 @@ impl LitentryMultiSignature {
_ => false,
}
}

// https://github.com/solana-labs/solana/blob/master/docs/src/proposals/off-chain-message-signing.md
fn verify_solana(&self, msg: &[u8], signer: &Address32) -> bool {
match (self, signer) {
(Self::Ed25519(ref sig), who) => match ed25519::Public::from_slice(who.as_ref()) {
Ok(signer) => sig.verify(msg, &signer),
Err(()) => false,
},
_ => false,
}
}
}

pub fn verify_evm_signature(msg: &[u8], sig: &EthereumSignature, who: &Address20) -> bool {
Expand Down Expand Up @@ -270,4 +282,20 @@ mod tests {
&pubkey_ref.try_into().unwrap()
));
}

#[test]
fn verify_solana_signature_works() {
let signer =
Identity::from_did("did:litentry:solana:E9SegbpSr21FPLbUhoTNH6C2ja7KDkptybqSaT84wMH6")
.unwrap();
let signature: [u8; 64] = [
62, 25, 148, 186, 53, 137, 248, 174, 149, 187, 225, 24, 186, 48, 24, 109, 100, 27, 149,
196, 66, 5, 222, 140, 22, 16, 136, 239, 154, 22, 133, 96, 79, 2, 180, 106, 150, 112,
116, 11, 6, 35, 32, 4, 145, 240, 54, 130, 206, 193, 200, 57, 241, 112, 35, 122, 226,
97, 174, 231, 221, 13, 98, 2,
];
let result = LitentryMultiSignature::Ed25519(ed25519::Signature::from_raw(signature))
.verify(b"test message", &signer);
assert_eq!(result, true);
}
}
24 changes: 24 additions & 0 deletions tee-worker/docker/lit-di-solana-identity-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
services:
lit-di-solana-identity-test:
image: litentry/litentry-cli:latest
container_name: litentry-di-solana-identity-test
volumes:
- ../ts-tests:/ts-tests
- ../client-api:/client-api
- ../cli:/usr/local/worker-cli
build:
context: ..
dockerfile: build.Dockerfile
target: deployed-client
depends_on:
litentry-node:
condition: service_healthy
litentry-worker-1:
condition: service_healthy
networks:
- litentry-test-network
entrypoint: "bash -c '/usr/local/worker-cli/lit_ts_integration_test.sh di_solana_identity.test.ts 2>&1' "
restart: "no"
networks:
litentry-test-network:
driver: bridge
28 changes: 28 additions & 0 deletions tee-worker/litentry/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ impl LitentryMultiSignature {
|| self.verify_substrate(msg, address),
Identity::Evm(address) => self.verify_evm(msg, address),
Identity::Bitcoin(address) => self.verify_bitcoin(msg, address),
Identity::Solana(address) => self.verify_solana(msg, address),
_ => false,
}
}
Expand Down Expand Up @@ -163,6 +164,17 @@ impl LitentryMultiSignature {
_ => false,
}
}

// https://github.com/solana-labs/solana/blob/master/docs/src/proposals/off-chain-message-signing.md
fn verify_solana(&self, msg: &[u8], signer: &Address32) -> bool {
match (self, signer) {
(Self::Ed25519(ref sig), who) => match ed25519::Public::from_slice(who.as_ref()) {
Ok(signer) => sig.verify(msg, &signer),
Err(()) => false,
},
_ => false,
}
}
}

pub fn verify_evm_signature(msg: &[u8], sig: &EthereumSignature, who: &Address20) -> bool {
Expand Down Expand Up @@ -280,4 +292,20 @@ mod tests {
&pubkey_ref.try_into().unwrap()
));
}

#[test]
fn verify_solana_signature_works() {
let signer =
Identity::from_did("did:litentry:solana:E9SegbpSr21FPLbUhoTNH6C2ja7KDkptybqSaT84wMH6")
.unwrap();
let signature: [u8; 64] = [
62, 25, 148, 186, 53, 137, 248, 174, 149, 187, 225, 24, 186, 48, 24, 109, 100, 27, 149,
196, 66, 5, 222, 140, 22, 16, 136, 239, 154, 22, 133, 96, 79, 2, 180, 106, 150, 112,
116, 11, 6, 35, 32, 4, 145, 240, 54, 130, 206, 193, 200, 57, 241, 112, 35, 122, 226,
97, 174, 231, 221, 13, 98, 2,
];
let result = LitentryMultiSignature::Ed25519(ed25519::Signature::from_raw(signature))
.verify(b"test message", &signer);
assert_eq!(result, true);
}
}
3 changes: 3 additions & 0 deletions tee-worker/ts-tests/integration-tests/common/common-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Wallet } from 'ethers';
import type { KeyringPair } from '@polkadot/keyring/types';
import type { HexString } from '@polkadot/util/types';
import { ECPairInterface } from 'ecpair';
import { Keypair } from '@solana/web3.js';
import { Signer } from './utils/crypto';
// If there are types already defined in the client-api, please avoid redefining these types.
// Instead, make every effort to use the types that have been generated within the client-api.
Expand All @@ -17,6 +18,7 @@ export interface Wallets {
evm: WalletType;
substrate: WalletType;
bitcoin: WalletType;
solana: WalletType;
}
export type IntegrationTestContext = {
tee: WebSocketAsPromised;
Expand All @@ -34,6 +36,7 @@ export type Web3Wallets = {
substrateWallet: KeyringPair;
evmWallet: Wallet;
bitcoinWallet: ECPairInterface;
solanaWallet: Keypair;
};

export type JsonRpcRequest = {
Expand Down
14 changes: 12 additions & 2 deletions tee-worker/ts-tests/integration-tests/common/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import type { KeyringPair } from '@polkadot/keyring/types';
import type { HexString } from '@polkadot/util/types';
import './config';
import { IntegrationTestContext, JsonRpcRequest } from './common-types';
import { randomBytes } from 'crypto';
import { createHash, randomBytes } from 'crypto';
import { ECPairFactory, ECPairInterface } from 'ecpair';
import * as ecc from 'tiny-secp256k1';
import { ethers, Wallet } from 'ethers';
import { EthersSigner, PolkadotSigner, BitcoinSigner } from './utils/crypto';
import { Keypair } from '@solana/web3.js';
import { EthersSigner, PolkadotSigner, BitcoinSigner, SolanaSigner } from './utils/crypto';
import { Wallets } from './common-types';
import type { ErrorDetail, StfError } from 'parachain-api';

Expand Down Expand Up @@ -60,17 +61,26 @@ export function genesisSubstrateWallet(name: string): KeyringPair {
return keyPair;
}

export function genesisSolanaWallet(name: string): Keypair {
let seed = createHash('sha256').update(name).digest();
seed = seed.subarray(0, 32);
const keyPair = Keypair.fromSeed(seed);
return keyPair;
}

export const createWeb3Wallets = (): Wallets => {
const wallets: Wallets = {
evm: {},
substrate: {},
bitcoin: {},
solana: {},
};
const walletNames = ['Alice', 'Bob', 'Charlie', 'Dave', 'Eve'];
for (const name of walletNames) {
wallets.evm[name] = new EthersSigner(randomEvmWallet());
wallets.substrate[name] = new PolkadotSigner(genesisSubstrateWallet(name));
wallets.bitcoin[name] = new BitcoinSigner(randomBitcoinWallet());
wallets.solana[name] = new SolanaSigner(genesisSolanaWallet(name));
}

return wallets;
Expand Down
42 changes: 42 additions & 0 deletions tee-worker/ts-tests/integration-tests/common/utils/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import crypto from 'crypto';
import { KeyringPair } from '@polkadot/keyring/types';
import { ethers } from 'ethers';
import { blake2AsU8a } from '@polkadot/util-crypto';
import { Keypair } from '@solana/web3.js';
import nacl from 'tweetnacl';
import { IntegrationTestContext } from './../common-types';
import { buildIdentityHelper } from './identity-helper';
import { ECPairInterface } from 'ecpair';
import * as bitcoinMessage from 'bitcoinjs-message';
import { isHexString } from 'ethers/lib/utils';
export type KeypairType = 'ed25519' | 'sr25519' | 'ecdsa' | 'ethereum' | 'bitcoin';

export function encryptWithTeeShieldingKey(teeShieldingKey: KeyObject, plaintext: Uint8Array): Buffer {
Expand Down Expand Up @@ -165,3 +168,42 @@ export class BitcoinSigner implements Signer {
return buildIdentityHelper(u8aToHex(this.getAddressRaw()), 'Bitcoin', context);
}
}

export class SolanaSigner implements Signer {
keypair: Keypair;

constructor(keypair: Keypair) {
this.keypair = keypair;
}

getAddressRaw(): Uint8Array {
return this.keypair.publicKey.toBytes();
}

sign(message: HexString | string | Uint8Array): Promise<Uint8Array> {
return new Promise((resolve) =>
resolve(
nacl.sign.detached(
isHexString(message)
? hexToU8a(message as HexString)
: isString(message)
? stringToU8a(message)
: message,
this.keypair.secretKey
)
)
);
}

type(): KeypairType {
return 'ed25519';
}

getAddressInSubstrateFormat(): Uint8Array {
return this.getAddressRaw();
}

getIdentity(context: IntegrationTestContext): Promise<CorePrimitivesIdentity> {
return buildIdentityHelper(u8aToHex(this.getAddressRaw()), 'Solana', context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export async function buildValidations(
signerIdentitity: CorePrimitivesIdentity,
linkIdentity: CorePrimitivesIdentity,
startingSidechainNonce: number,
network: 'ethereum' | 'substrate' | 'twitter' | 'bitcoin',
network: 'ethereum' | 'substrate' | 'twitter' | 'bitcoin' | 'solana',
signer?: Signer
): Promise<LitentryValidationData> {
const validationNonce = startingSidechainNonce++;
Expand Down Expand Up @@ -131,5 +131,24 @@ export async function buildValidations(
return context.api.createType('LitentryValidationData', twitterValidationData);
}

if (network === 'solana') {
const solanaValidationData = {
Web3Validation: {
Solana: {
message: '' as HexString,
signature: {
Ed25519: '' as HexString,
},
},
},
};
console.log('post verification msg to solana: ', msg);
solanaValidationData.Web3Validation.Solana.message = msg;
const solanaSignature = await signer!.sign(msg);
solanaValidationData!.Web3Validation.Solana.signature.Ed25519 = u8aToHex(solanaSignature);

return context.api.createType('LitentryValidationData', solanaValidationData);
}

throw new Error(`[buildValidation]: Unsupported network ${network}.`);
}
Loading

0 comments on commit d3e0f30

Please sign in to comment.