import { AuthorAddress, AuthorKeypair, Base32String,} from "../util/doc-types.ts";import { ICrypto, KeypairBytes } from "./crypto-types.ts";import { isErr, ValidationError } from "../util/errors.ts";
import { randomId } from "../util/misc.ts";import { base32BytesToString, base32StringToBytes } from "./base32.ts";import { decodeAuthorKeypairToBytes } from "./keypair.ts";import { assembleAuthorAddress, checkAuthorIsValid, parseAuthorAddress,} from "../core-validators/addresses.ts";
import { GlobalCryptoDriver } from "./global-crypto-driver.ts";
import { Logger } from "../util/log.ts";let logger = new Logger("crypto", "cyan");
export const Crypto: ICrypto = class { static async sha256base32( input: string | Uint8Array, ): Promise<Base32String> { const b32 = await GlobalCryptoDriver.sha256(input);
return base32BytesToString(b32); }
static async generateAuthorKeypair( name: string, ): Promise<AuthorKeypair | ValidationError> { logger.debug(`generateAuthorKeypair("${name}")`); const keypairBytes = await GlobalCryptoDriver .generateKeypairBytes(); const keypairFormatted = { address: assembleAuthorAddress( name, base32BytesToString(keypairBytes.pubkey), ), secret: base32BytesToString(keypairBytes.secret), }; const err = checkAuthorIsValid(keypairFormatted.address); if (isErr(err)) return err; return keypairFormatted; }
static async sign( keypair: AuthorKeypair, msg: string | Uint8Array, ): Promise<Base32String | ValidationError> { logger.debug(`sign`); try { let keypairBytes = decodeAuthorKeypairToBytes(keypair); if (isErr(keypairBytes)) return keypairBytes;
const signed = await GlobalCryptoDriver.sign(keypairBytes, msg);
return base32BytesToString(signed); } catch (err: any) { return new ValidationError( "unexpected error while signing: " + err.message, ); } }
static async verify( authorAddress: AuthorAddress, sig: Base32String, msg: string | Uint8Array, ): Promise<boolean> { logger.debug(`verify`); try { let authorParsed = parseAuthorAddress(authorAddress); if (isErr(authorParsed)) return false; return GlobalCryptoDriver.verify( base32StringToBytes(authorParsed.pubkey), base32StringToBytes(sig), msg, ); } catch (err) { return false; } }
static async checkAuthorKeypairIsValid( keypair: AuthorKeypair, ): Promise<true | ValidationError> { logger.debug(`checkAuthorKeypairIsValid`); try { if ( typeof keypair.address !== "string" || typeof keypair.secret !== "string" ) { return new ValidationError( "address and secret must be strings", ); } let addressErr = checkAuthorIsValid(keypair.address); if (isErr(addressErr)) return addressErr;
let msg = "a test message to sign. " + randomId(); let sig = await this.sign(keypair, msg); if (isErr(sig)) return sig;
let isValid = await this.verify(keypair.address, sig, msg); if (isValid === false) { return new ValidationError("pubkey does not match secret"); }
return true; } catch (err: any) { return new ValidationError( "unexpected error in checkAuthorKeypairIsValid: " + err.message, ); } }};